[
  {
    "path": ".github/ops/mysql/Dockerfile",
    "content": "ARG DIALECT=mysql:8.0\n\nFROM $DIALECT as builder\n\nARG SERVER=mysqld\nENV MYSQL_ROOT_PASSWORD=pass\n\n# Remove the last line of the entry point script, leaving the initialization code but omitting actually starting the db.\nRUN sed -i 's/exec \"$@\"/echo \"not running $@\"/' /usr/local/bin/docker-entrypoint.sh\nRUN /usr/local/bin/docker-entrypoint.sh ${SERVER}\n\nFROM $DIALECT\n\nCOPY --from=builder /var/lib/mysql /var/lib/mysql\n"
  },
  {
    "path": ".github/workflows/cd-docker-push-cockroach_oss.yaml",
    "content": "name: CD - Build Docker - Cockroach - Community Edition\non:\n  pull_request:\n  push:\n    branches:\n      - master\n\nenv:\n  CRDB_VERSIONS: v21.2.11 v22.1.0\n\njobs:\n  build-services:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Log in to registry\n        run: echo \"${{ secrets.GITHUB_TOKEN }}\" | docker login ghcr.io -u $ --password-stdin\n      - name: \"build cockroach image\"\n        run: |\n          VER=\"${{ env.CRDB_VERSIONS }}\"\n          for i in $VER\n          do\n            :\n            if ! docker manifest inspect ghcr.io/ariga/cockroachdb-single-node:$i; then\n              go run internal/ci/cockroach/main.go $i > internal/ci/cockroach/Dockerfile\n              docker build -t ghcr.io/ariga/cockroachdb-single-node:$i internal/ci/cockroach/\n              docker push ghcr.io/ariga/cockroachdb-single-node:$i\n            else\n              echo image already exists\n            fi\n          done"
  },
  {
    "path": ".github/workflows/cd-docker-push-mysql_oss.yaml",
    "content": "name: CD - Build Docker - MySQL Quick Boot - Community Edition\non:\n  push:\n    paths:\n      - .github/ops/mysql/**\n      - .github/workflows/cd-docker-push-mysql_oss.yaml\n    branches:\n      - master\n  schedule:\n    # Runs at 00:00 on Sunday\n    - cron: '0 0 * * 0'\n  workflow_dispatch:\njobs:\n  push-docker:\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - dialect: mysql:latest\n          - dialect: mysql:5.6\n            platforms: linux/amd64\n          - dialect: mysql:5.6.35\n            platforms: linux/amd64\n          - dialect: mysql:5.7\n            platforms: linux/amd64\n          - dialect: mysql:5.7.26\n            platforms: linux/amd64\n          - dialect: mysql:8\n          - dialect: mysql:8.0.40\n          - dialect: mysql:8.4\n          - dialect: mysql:8.4.0\n          - dialect: mysql:8.3\n          - dialect: mysql:8.3.0\n          - dialect: mariadb:latest\n            build-args: SERVER=mariadbd\n          - dialect: mariadb:10.2\n          - dialect: mariadb:10.2.32\n          - dialect: mariadb:10.3\n          - dialect: mariadb:10.3.13\n            platforms: linux/amd64\n          - dialect: mariadb:10.7\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Login to Docker Hub\n        uses: docker/login-action@v1\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      - name: Set up QEMU\n        uses: docker/setup-qemu-action@v2\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v2\n      - name: Build & Push ${{ matrix.dialect }} Docker Image\n        uses: docker/build-push-action@v2\n        with:\n          context: .\n          file: ./.github/ops/mysql/Dockerfile\n          push: true\n          tags: arigaio/${{ matrix.dialect }}\n          platforms: ${{ matrix.platforms || 'linux/amd64,linux/arm64' }}\n          build-args: |\n            DIALECT=${{ matrix.dialect }}\n            ${{ matrix.build-args }}\n"
  },
  {
    "path": ".github/workflows/ci-dialect_oss.yaml",
    "content": "# # # # # # # # # # # # # # # #\n# CODE GENERATED - DO NOT EDIT\n# # # # # # # # # # # # # # # #\nname: CI - Dialect Tests - Community Edition\non:\n  workflow_call:\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}-dialect\n  cancel-in-progress: true\nenv:\n  ATLAS_NO_UPGRADE_SUGGESTIONS: 1\njobs:\n  integration-mysql56:\n    runs-on: ubuntu-latest\n    services:\n      mysql56:\n        image: mysql:5.6.35\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n        ports:\n          - 3306:3306\n        options: >-\n          --health-cmd \"mysqladmin ping -ppass\"\n          --health-interval 10s\n          --health-start-period 10s\n          --health-timeout 5s\n          --health-retries 10\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for mysql56\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"MySQL\" -version=\"mysql56\" -timeout 15m ./...\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n  integration-mysql57:\n    runs-on: ubuntu-latest\n    services:\n      mysql57:\n        image: mysql:5.7.26\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n        ports:\n          - 3307:3306\n        options: >-\n          --health-cmd \"mysqladmin ping -ppass\"\n          --health-interval 10s\n          --health-start-period 10s\n          --health-timeout 5s\n          --health-retries 10\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for mysql57\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"MySQL\" -version=\"mysql57\" -timeout 15m ./...\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n  integration-mysql8:\n    runs-on: ubuntu-latest\n    services:\n      mysql8:\n        image: mysql:8\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n        ports:\n          - 3308:3306\n        options: >-\n          --health-cmd \"mysqladmin ping -ppass\"\n          --health-interval 10s\n          --health-start-period 10s\n          --health-timeout 5s\n          --health-retries 10\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for mysql8\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"MySQL\" -version=\"mysql8\" -timeout 15m ./...\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n  integration-maria107:\n    runs-on: ubuntu-latest\n    services:\n      maria107:\n        image: mariadb:10.7\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n        ports:\n          - 4306:3306\n        options: >-\n          --health-cmd \"mysqladmin ping -ppass\"\n          --health-interval 10s\n          --health-start-period 10s\n          --health-timeout 5s\n          --health-retries 10\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for maria107\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"MySQL\" -version=\"maria107\" -timeout 15m ./...\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n  integration-maria102:\n    runs-on: ubuntu-latest\n    services:\n      maria102:\n        image: mariadb:10.2.32\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n        ports:\n          - 4307:3306\n        options: >-\n          --health-cmd \"mysqladmin ping -ppass\"\n          --health-interval 10s\n          --health-start-period 10s\n          --health-timeout 5s\n          --health-retries 10\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for maria102\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"MySQL\" -version=\"maria102\" -timeout 15m ./...\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n  integration-maria103:\n    runs-on: ubuntu-latest\n    services:\n      maria103:\n        image: mariadb:10.3.13\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n        ports:\n          - 4308:3306\n        options: >-\n          --health-cmd \"mysqladmin ping -ppass\"\n          --health-interval 10s\n          --health-start-period 10s\n          --health-timeout 5s\n          --health-retries 10\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for maria103\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"MySQL\" -version=\"maria103\" -timeout 15m ./...\n        env:\n          MYSQL_DATABASE: test\n          MYSQL_ROOT_PASSWORD: pass\n  integration-postgres-ext-postgis:\n    runs-on: ubuntu-latest\n    services:\n      postgres-ext-postgis:\n        image: postgis/postgis:latest\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n        ports:\n          - 5429:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for postgres-ext-postgis\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"Postgres\" -version=\"postgres-ext-postgis\" -timeout 15m ./...\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n  integration-postgres10:\n    runs-on: ubuntu-latest\n    services:\n      postgres10:\n        image: postgres:10\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n        ports:\n          - 5430:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for postgres10\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"Postgres\" -version=\"postgres10\" -timeout 15m ./...\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n  integration-postgres11:\n    runs-on: ubuntu-latest\n    services:\n      postgres11:\n        image: postgres:11\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n        ports:\n          - 5431:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for postgres11\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"Postgres\" -version=\"postgres11\" -timeout 15m ./...\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n  integration-postgres12:\n    runs-on: ubuntu-latest\n    services:\n      postgres12:\n        image: postgres:12.3\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n        ports:\n          - 5432:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for postgres12\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"Postgres\" -version=\"postgres12\" -timeout 15m ./...\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n  integration-postgres13:\n    runs-on: ubuntu-latest\n    services:\n      postgres13:\n        image: postgres:13.1\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n        ports:\n          - 5433:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for postgres13\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"Postgres\" -version=\"postgres13\" -timeout 15m ./...\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n  integration-postgres14:\n    runs-on: ubuntu-latest\n    services:\n      postgres14:\n        image: postgres:14\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n        ports:\n          - 5434:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for postgres14\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"Postgres\" -version=\"postgres14\" -timeout 15m ./...\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n  integration-postgres15:\n    runs-on: ubuntu-latest\n    services:\n      postgres15:\n        image: postgres:15\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n        ports:\n          - 5435:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for postgres15\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"Postgres\" -version=\"postgres15\" -timeout 15m ./...\n        env:\n          POSTGRES_DB: test\n          POSTGRES_PASSWORD: pass\n  integration-sqlite:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for sqlite\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"SQLite.*\" -version=\"sqlite\" -timeout 15m ./...\n  integration-tidb5:\n    runs-on: ubuntu-latest\n    services:\n      tidb5:\n        image: pingcap/tidb:v5.4.0\n        ports:\n          - 4309:4000\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for tidb5\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"TiDB\" -version=\"tidb5\" -timeout 15m ./...\n  integration-tidb6:\n    runs-on: ubuntu-latest\n    services:\n      tidb6:\n        image: pingcap/tidb:v6.0.0\n        ports:\n          - 4310:4000\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for tidb6\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"TiDB\" -version=\"tidb6\" -timeout 15m ./...\n  integration-cockroach:\n    runs-on: ubuntu-latest\n    services:\n      cockroach:\n        image: ghcr.io/ariga/cockroachdb-single-node:v21.2.11\n        ports:\n          - 26257:26257\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for cockroach\n        working-directory: internal/integration\n        run: go test -race -count=2 -v -run=\"Cockroach\" -version=\"cockroach\" -timeout 15m ./...\n"
  },
  {
    "path": ".github/workflows/ci-go_oss.yaml",
    "content": "# # # # # # # # # # # # # # # #\n# CODE GENERATED - DO NOT EDIT\n# # # # # # # # # # # # # # # #\nname: CI - General - Community Edition\non:\n  pull_request:\n    paths-ignore:\n      - 'doc/**'\n      - 'ops/**'\n  push:\n    branches:\n      - master\n    paths-ignore:\n      - 'doc/**'\n      - 'ops/**'\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\nenv:\n  ATLAS_NO_UPGRADE_SUGGESTIONS: 1\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run linters\n        uses: golangci/golangci-lint-action@v6\n        with:\n          args: --verbose\n\n  generate-cmp:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Install stringer\n        run: go install golang.org/x/tools/cmd/stringer@latest\n      - name: run \"go generate ./...\"\n        run: go generate ./...\n      - name: go generate cmd/atlas\n        working-directory: cmd/atlas\n        run: go generate ./...\n      - name: Verify generated files are checked-in properly\n        run: |\n          status=$(git status --porcelain | grep -v \"go.\\(sum\\|mod\\)\" | cat)\n          if [ -n \"$status\" ]; then\n            echo \"you need to run 'go generate ./...' and commit the changes\"\n            echo \"$status\"\n            exit 1\n          fi\n  unit:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        go: [ \"1.22\" ]\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version: ${{ matrix.go }}\n      - name: Run sql tests\n        run: go test -race ./...\n        working-directory: sql\n      - name: Run schemahcl tests\n        run: go test -race ./...\n        working-directory: schemahcl\n\n  cli:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run cli tests\n        run: go test -race ./...\n        working-directory: cmd/atlas\n\n  integration:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Run integration tests for HCL\n        working-directory: internal/integration/hclsqlspec\n        run: go test -race -count=2 -v ./...\n\n  dialect-integration:\n    needs: [lint, generate-cmp, unit, cli, integration]\n    uses: ./.github/workflows/ci-dialect_oss.yaml\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/ci-revisions_oss.yaml",
    "content": "# # # # # # # # # # # # # # # #\n# CODE GENERATED - DO NOT EDIT\n# # # # # # # # # # # # # # # #\nname: CI - Revisions - Community Edition\non:\n  pull_request:\n    paths:\n      - 'cmd/atlas/internal/migrate/ent/**'\n  push:\n    branches:\n      - master\n    paths:\n      - 'cmd/atlas/internal/migrate/ent/**'\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}\n  cancel-in-progress: true\njobs:\n  revisions:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      - name: Checkout origin/master\n        run: git checkout origin/master\n      - name: Create revisions from master\n        run: go run . migrate apply --dir file://internal/cmdapi/testdata/sqlite --url sqlite://db?_fk=1\n        working-directory: cmd/atlas\n      - name: Checkout previous HEAD\n        run: git checkout -\n      - name: Migrate revisions table to HEAD\n        run: go run . migrate apply --dir file://internal/cmdapi/testdata/sqlite --url sqlite://db?_fk=1\n        working-directory: cmd/atlas"
  },
  {
    "path": ".github/workflows/ci-sdk.yml",
    "content": "name: Go SDK CI\non:\n  push:\n    branches:\n      - master\n  pull_request:\njobs:\n  golangci-lint:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        module: [\"atlasexec\", \"sdk\"]\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: ./go.mod\n      - name: Run Go linters\n        uses: golangci/golangci-lint-action@v6\n        with:\n          working-directory: ${{ matrix.module }}\n          args: --verbose --timeout 15m\n  \n  unit-tests:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        module: [\"atlasexec\", \"sdk\"]\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: ./go.mod\n      - uses: ariga/setup-atlas@v0\n        with:\n          cloud-token: ${{ secrets.ATLAS_TOKEN }}\n        env:\n          ATLAS_DEBUG: \"true\"\n      - name: Run tests\n        run: go test -race ./...\n        working-directory: ${{ matrix.module }}\n  \n  e2e-tests:\n    runs-on: ubuntu-latest\n    services:\n      postgres:\n        image: postgres\n        env:\n          POSTGRES_PASSWORD: pass\n        ports:\n          - 5432:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: ./go.mod\n      - uses: ariga/setup-atlas@v0\n        with:\n          cloud-token: ${{ secrets.ATLAS_TOKEN }}\n        env:\n          ATLAS_DEBUG: \"true\"\n      - name: Run e2e tests\n        run: go test ./internal/e2e\n        working-directory: atlasexec\n        env:\n          ATLASEXEC_E2ETEST: \"1\"\n          ATLASEXEC_E2ETEST_ATLAS_PATH: atlas\n          ATLASEXEC_E2ETEST_POSTGRES_URL: \"postgres://postgres:pass@localhost:5432/postgres?search_path=public&sslmode=disable\"\n"
  },
  {
    "path": ".golangci.yml",
    "content": "run:\n  timeout: 3m\n\nissues:\n  include:\n    - EXC0012\n  exclude:\n    - G601\n    - G404\n    - redefines-builtin-id\n  exclude-rules:\n    - path: _test\\.go\n      linters:\n        - gosec\n    - path: sql/migrate/dir.go\n      linters:\n        - gosec\n    - path: sql/mysql/inspect_oss.go\n      linters:\n        - gosec\n    - path: sql/migrate/lex.go\n      linters:\n        - revive\n    - path: sql/internal/sqlx/diff.go\n      linters:\n        - revive\n\nlinters-settings:\n  goheader:\n    template: |-\n      Copyright 2021-present The Atlas Authors. All rights reserved.\n      This source code is licensed under the Apache 2.0 license found\n      in the LICENSE file in the root directory of this source tree.\n\nlinters:\n  disable-all: true\n  enable:\n    - gosec\n    - revive\n    - goheader\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "README.md",
    "content": "# Atlas - Manage Your Database Schema as Code\n\n[![Twitter](https://img.shields.io/twitter/url.svg?label=Follow%20%40atlasgo_io&style=social&url=https%3A%2F%2Ftwitter.com%2Fatlasgo_io)](https://twitter.com/atlasgo_io)\n[![Discord](https://img.shields.io/discord/930720389120794674?label=discord&logo=discord&style=flat-square&logoColor=white)](https://discord.com/invite/zZ6sWVg6NT)\n\n<p>\n  <a href=\"https://atlasgo.io\" target=\"_blank\">\n    <img alt=\"Atlas banner\" src=\"https://github.com/ariga/atlas/assets/7413593/2e27cb81-bad6-491a-8d9c-20920995a186\">\n  </a>\n</p>\n\nAtlas is a language-agnostic tool for managing and migrating database schemas using modern DevOps principles.\nIt offers two workflows:\n\n- **Declarative**: Similar to Terraform, Atlas compares the current state of the database to the desired state, as\n  defined in an [HCL], [SQL], or [ORM] schema. Based on this comparison, it generates and executes a migration plan to\n  transition the database to its desired state.\n\n- **Versioned**: Unlike other tools, Atlas automatically plans schema migrations for you. Users can describe their desired\n  database schema in [HCL], [SQL], or their chosen [ORM], and by utilizing Atlas, they can plan, lint, and apply the\n  necessary migrations to the database.\n\n\n## Supported Databases\n\n[PostgreSQL](https://atlasgo.io/guides/postgres) ·\n[MySQL](https://atlasgo.io/guides/mysql) ·\n[MariaDB](https://atlasgo.io/guides/mysql) ·\n[SQL Server](https://atlasgo.io/guides/mssql) ·\n[SQLite](https://atlasgo.io/guides/sqlite) ·\n[ClickHouse](https://atlasgo.io/guides/clickhouse) ·\n[Redshift](https://atlasgo.io/guides/redshift) ·\n[Oracle](https://atlasgo.io/guides/oracle) ·\n[Snowflake](https://atlasgo.io/guides/snowflake) ·\n[CockroachDB](https://atlasgo.io/guides/cockroachdb) ·\n[TiDB](https://atlasgo.io/guides/mysql) ·\n[Databricks](https://atlasgo.io/guides/databricks) ·\n[Spanner](https://atlasgo.io/guides/spanner) ·\n[Aurora DSQL](https://atlasgo.io/guides/dsql) ·\n[Azure Fabric](https://atlasgo.io/guides/azure-fabric)\n\n## Installation\n\n**macOS + Linux:**\n\n```bash\ncurl -sSf https://atlasgo.sh | sh\n```\n\n**Homebrew:**\n\n```bash\nbrew install ariga/tap/atlas\n```\n\n**Docker:**\n\n```bash\ndocker pull arigaio/atlas\n```\n\n**NPM:**\n\n```bash\nnpx @ariga/atlas\n```\n\nSee [installation docs](https://atlasgo.io/getting-started#installation) for all platforms.\n\n## Key Features\n\n- **[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.\n- **[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.\n- **[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.\n- **[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.\n- **[Data management](https://atlasgo.io/atlas-schema/sql)**: Manage seed and lookup data declaratively alongside your schema.\n- **[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.\n- **[Testing framework](https://atlasgo.io/testing/schema)**: Unit test schema logic (functions, views, triggers, procedures) and [migration behavior](https://atlasgo.io/testing/migrate).\n- **[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.\n- **[Multi-tenancy](https://atlasgo.io/guides/multi-tenancy)**: Built-in support for multi-tenant database migrations.\n- **[Drift detection](https://atlasgo.io/monitoring)**: Monitoring as Code with automatic schema drift detection and remediation.\n- **[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.\n\n## Getting Started\n\nGet started with Atlas by following the [Getting Started](https://atlasgo.io/getting-started/) docs.\n\nInspect an existing database schema:\n```shell\natlas schema inspect -u \"postgres://localhost:5432/mydb\"\n```\n\nApply your desired schema to the database:\n```shell\natlas schema apply \\\n  --url \"postgres://localhost:5432/mydb\" \\\n  --to file://schema.hcl \\\n  --dev-url \"docker://postgres/16/dev\"\n```\n\n📖 [Getting Started docs](https://atlasgo.io/getting-started/)\n\n## Migration Linting\n\nAtlas ships with 50+ built-in [analyzers](https://atlasgo.io/lint/analyzers) that review your migration files\nand catch issues before they reach production. Analyzers detect [destructive changes](https://atlasgo.io/lint/analyzers#destructive-changes)\nlike dropped tables or columns, [data-dependent modifications](https://atlasgo.io/lint/analyzers#data-dependent-changes)\nsuch as adding non-nullable columns without defaults, and database-specific risks like table locks\nand table rewrites that can cause downtime on busy tables. You can also define\nyour own [custom policy rules](https://atlasgo.io/lint/rules).\n\n```bash\natlas migrate lint --dev-url \"docker://postgres/16/dev\"\n```\n\n## Schema Testing\n\n[Test](https://atlasgo.io/testing/schema) database logic (functions, views, triggers, procedures) and\n[data migrations](https://atlasgo.io/testing/migrate) with `.test.hcl` files:\n\n```hcl\ntest \"schema\" \"postal\" {\n  # Valid postal codes pass\n  exec {\n    sql = \"SELECT '12345'::us_postal_code\"\n  }\n  # Invalid postal codes fail\n  catch {\n    sql = \"SELECT 'hello'::us_postal_code\"\n  }\n}\n\ntest \"schema\" \"seed\" {\n  for_each = [\n    {input: \"hello\", expected: \"HELLO\"},\n    {input: \"world\", expected: \"WORLD\"},\n  ]\n  exec {\n    sql    = \"SELECT upper('${each.value.input}')\"\n    output = each.value.expected\n  }\n}\n```\n\n```bash\natlas schema test --dev-url \"docker://postgres/16/dev\"\n```\n\n📖 [Testing docs](https://atlasgo.io/testing/schema)\n\n## Security-as-Code\n\nManage database [roles, permissions](https://atlasgo.io/guides/postgres/security-declarative), and\n[row-level security](https://atlasgo.io/guides/postgres/row-level-security) as version-controlled code:\n\n```hcl\nrole \"app_readonly\" {\n  comment = \"Read-only access for reporting\"\n}\n\nrole \"app_writer\" {\n  comment   = \"Read-write access for the application\"\n  member_of = [role.app_readonly]\n}\n\nuser \"api_user\" {\n  password   = var.api_password\n  conn_limit = 20\n  comment    = \"Application API service account\"\n  member_of  = [role.app_writer]\n}\n\npermission {\n  for_each   = [table.orders, table.products, table.users]\n  for        = each.value\n  to         = role.app_readonly\n  privileges = [SELECT]\n}\n\npolicy \"tenant_isolation\" {\n  on    = table.orders\n  for   = ALL\n  to    = [\"app_writer\"]\n  using = \"(tenant_id = current_setting('app.current_tenant')::integer)\"\n  check = \"(tenant_id = current_setting('app.current_tenant')::integer)\"\n}\n```\n\n📖 [Security-as-Code docs](https://atlasgo.io/guides/postgres/security-declarative)\n\n## Data Management\n\nManage seed and lookup data declaratively alongside your schema:\n\n```sql\nCREATE TABLE countries (\n  id INT PRIMARY KEY,\n  code VARCHAR(2) NOT NULL,\n  name VARCHAR(100) NOT NULL\n);\n\nINSERT INTO countries (id, code, name) VALUES\n  (1, 'US', 'United States'),\n  (2, 'IL', 'Israel'),\n  (3, 'DE', 'Germany');\n```\n\n📖 [Data management docs](https://atlasgo.io/atlas-schema/sql)\n\n## ORM Support\n\nDefine your schema in any of the 16 supported ORMs. Atlas reads your models and generates migrations:\n\n| Language | ORMs |\n|----------|------|\n| 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) |\n| 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) |\n| Python | [Django](https://atlasgo.io/guides/orms/django), [SQLAlchemy](https://atlasgo.io/guides/orms/sqlalchemy) |\n| Java | [Hibernate](https://atlasgo.io/guides/orms/hibernate) |\n| .NET | [EF Core](https://atlasgo.io/guides/orms/efcore) |\n| PHP | [Doctrine](https://atlasgo.io/guides/orms/doctrine) |\n\n📖 [ORM integration docs](https://atlasgo.io/orms)\n\n## Integrations\n\nLint, test, and apply migrations automatically in your CI/CD pipeline or infrastructure-as-code workflow:\n\n| Integration | Docs |\n|-------------|------|\n| GitHub Actions | [Versioned guide](https://atlasgo.io/guides/ci-platforms/github-versioned) · [Declarative guide](https://atlasgo.io/guides/ci-platforms/github-declarative) |\n| GitLab CI | [Versioned guide](https://atlasgo.io/guides/ci-platforms/gitlab-versioned) · [Declarative guide](https://atlasgo.io/guides/ci-platforms/gitlab-declarative) |\n| CircleCI | [Versioned guide](https://atlasgo.io/guides/ci-platforms/circleci-versioned) · [Declarative guide](https://atlasgo.io/guides/ci-platforms/circleci-declarative) |\n| Bitbucket Pipes | [Versioned guide](https://atlasgo.io/guides/ci-platforms/bitbucket-versioned) · [Declarative guide](https://atlasgo.io/guides/ci-platforms/bitbucket-declarative) |\n| Azure DevOps | [GitHub repos](https://atlasgo.io/guides/ci-platforms/azure-devops-github) · [Azure repos](https://atlasgo.io/guides/ci-platforms/azure-devops-repos) |\n| Terraform Provider | [atlasgo.io/integrations/terraform-provider](https://atlasgo.io/integrations/terraform-provider) |\n| Kubernetes Operator | [atlasgo.io/integrations/kubernetes](https://atlasgo.io/integrations/kubernetes) |\n| ArgoCD | [atlasgo.io/guides/deploying/k8s-argo](https://atlasgo.io/guides/deploying/k8s-argo) |\n| Flux | [atlasgo.io/guides/deploying/k8s-flux](https://atlasgo.io/guides/deploying/k8s-flux) |\n| Crossplane | [atlasgo.io/guides/deploying/crossplane](https://atlasgo.io/guides/deploying/crossplane) |\n| Go SDK | [pkg.go.dev/ariga.io/atlas-go-sdk/atlasexec](https://pkg.go.dev/ariga.io/atlas-go-sdk/atlasexec) |\n\n### AI Agent Integration\n\nAtlas provides [Agent Skills](https://atlasgo.io/guides/ai-tools/agent-skills), an open standard for packaging\nmigration expertise for AI coding assistants:\n[Claude Code](https://atlasgo.io/guides/ai-tools/claude-code-instructions),\n[GitHub Copilot](https://atlasgo.io/guides/ai-tools/github-copilot-instructions),\n[Cursor](https://atlasgo.io/guides/ai-tools/cursor-rules),\n[OpenAI Codex](https://atlasgo.io/guides/ai-tools/codex-instructions). Learn more at [AI tools docs](https://atlasgo.io/guides/ai-tools).\n\n## CLI Usage\n\n### `schema inspect`\n\n_**Easily inspect your database schema by providing a database URL and convert it to HCL, JSON, SQL, ERD, or other formats.**_\n\nInspect a specific MySQL schema and get its representation in Atlas DDL syntax:\n```shell\natlas schema inspect -u \"mysql://root:pass@localhost:3306/example\" > schema.hcl\n```\n\n<details><summary>Result</summary>\n\n```hcl\ntable \"users\" {\n  schema = schema.example\n  column \"id\" {\n    null = false\n    type = int\n  }\n  ...\n}\n```\n</details>\n\nInspect the entire MySQL database and get its JSON representation:\n```shell\natlas schema inspect \\\n  --url \"mysql://root:pass@localhost:3306/\" \\\n  --format '{{ json . }}' | jq\n```\n\n<details><summary>Result</summary>\n\n```json\n{\n  \"schemas\": [\n    {\n      \"name\": \"example\",\n      \"tables\": [\n        {\n          \"name\": \"users\",\n          \"columns\": [\n            ...\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n</details>\n\nInspect a specific PostgreSQL schema and get its ERD representation in Mermaid syntax:\n```shell\natlas schema inspect \\\n  --url \"postgres://root:pass@:5432/test?search_path=public&sslmode=disable\" \\\n  --format '{{ mermaid . }}'\n```\n\n```mermaid\nerDiagram\n    users {\n      int id PK\n      varchar name\n    }\n    blog_posts {\n      int id PK\n      varchar title\n      text body\n      int author_id FK\n    }\n    blog_posts }o--o| users : author_fk\n```\n\nUse the [split format](https://atlasgo.io/inspect/database-to-code) for one-file-per-object output:\n\n```bash\natlas schema inspect -u '<url>' --format '{{ sql . | split | write }}'\n```\n\n```\n├── schemas\n│   └── public\n│       ├── public.sql\n│       ├── tables\n│       │   ├── profiles.sql\n│       │   └── users.sql\n│       ├── functions\n│       └── types\n└── main.sql\n```\n\n📖 [Schema inspection docs](https://atlasgo.io/inspect)\n\n### `schema diff`\n\n_**Compare two schema states and get a migration plan to transform one into the other. A state can be specified using a\ndatabase URL, HCL, SQL, or ORM schema, or a migration directory.**_\n\n```shell\natlas schema diff \\\n  --from \"postgres://postgres:pass@:5432/test?search_path=public&sslmode=disable\" \\\n  --to file://schema.hcl \\\n  --dev-url \"docker://postgres/15/test\"\n```\n\n📖 [Declarative workflow docs](https://atlasgo.io/declarative/apply)\n\n### `schema apply`\n\n_**Generate a migration plan and apply it to the database to bring it to the desired state. The desired state can be\nspecified using a database URL, HCL, SQL, or ORM schema, or a migration directory.**_\n\n```shell\natlas schema apply \\\n  --url mysql://root:pass@:3306/db1 \\\n  --to file://schema.hcl \\\n  --dev-url docker://mysql/8/db1\n```\n\n<details><summary>Result</summary>\n\n```shell\n-- Planned Changes:\n-- Modify \"users\" table\nALTER TABLE `db1`.`users` DROP COLUMN `d`, ADD COLUMN `c` int NOT NULL;\nUse the arrow keys to navigate: ↓ ↑ → ←\n? Are you sure?:\n  ▸ Apply\n    Abort\n```\n</details>\n\n📖 [Declarative workflow docs](https://atlasgo.io/declarative/apply)\n\n### `migrate diff`\n\n_**Write a new migration file to the migration directory that brings it to the desired state. The desired state can be\nspecified using a database URL, HCL, SQL, or ORM schema, or a migration directory.**_\n\n```shell\natlas migrate diff add_blog_posts \\\n  --dir file://migrations \\\n  --to file://schema.hcl \\\n  --dev-url docker://mysql/8/test\n```\n\n📖 [Versioned workflow docs](https://atlasgo.io/versioned/diff)\n\n### `migrate apply`\n\n_**Apply all or part of pending migration files in the migration directory on the database.**_\n\n```shell\natlas migrate apply \\\n  --url mysql://root:pass@:3306/db1 \\\n  --dir file://migrations\n```\n\n📖 [Versioned workflow docs](https://atlasgo.io/versioned/apply)\n\n## Supported Version Policy\n\nTo ensure the best performance, security and compatibility with the Atlas Cloud service, the Atlas team\nwill only support the two most recent minor versions of the CLI. For example, if the latest version is\n`v0.25`, the supported versions will be `v0.24` and `v0.25` (in addition to any patch releases and the\n\"canary\" release which is built twice a day).\n\n\n## Community\n\n[Documentation](https://atlasgo.io/getting-started) ·\n[Discord](https://discord.com/invite/zZ6sWVg6NT) ·\n[Twitter](https://twitter.com/atlasgo_io)\n\n[HCL]: https://atlasgo.io/atlas-schema/hcl\n[SQL]: https://atlasgo.io/atlas-schema/sql\n[ORM]: https://atlasgo.io/orms\n"
  },
  {
    "path": "atlasexec/README.md",
    "content": "# Atlas SDK for Go\n\n[![Go Reference](https://pkg.go.dev/badge/ariga.io/atlas-go-sdk/atlasexec.svg)](https://pkg.go.dev/ariga.io/atlas@master/atlasexec)\n\nAn SDK for building ariga/atlas providers in Go.\n\n## Installation\n\n```bash\ngo get -u ariga.io/atlas@master\n```\n\n## How to use\n\nTo use the SDK, you need to create a new client with your `migrations` folder and the `atlas` binary path.\n\n```go\npackage main\n\nimport (\n    ...\n    \"ariga.io/atlas/atlasexec\"\n)\n\nfunc main() {\n    // Create a new client\n    client, err := atlasexec.NewClient(\"my-migration-folder\", \"my-atlas-cli-path\")\n    if err != nil {\n        log.Fatalf(\"failed to create client: %v\", err)\n    }\n}\n```\n\n## APIs\n\nFor more information, refer to the documentation available at [GoDoc](https://pkg.go.dev/ariga.io/atlas@master/atlasexec#Client)"
  },
  {
    "path": "atlasexec/atlas.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"maps\"\n\t\"os\"\n\t\"os/exec\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n)\n\ntype (\n\t// Client is a client for the Atlas CLI.\n\tClient struct {\n\t\texecPath   string\n\t\tworkingDir string\n\t\tenv        Environ\n\t\tstdout     io.Writer\n\t\tstderr     io.Writer\n\t}\n\t// LoginParams are the parameters for the `login` command.\n\tLoginParams struct {\n\t\tToken     string\n\t\tGrantOnly bool // If true, runs `atlas login --grant-only` for offline token flow.\n\t}\n\t// WhoAmIParams are the parameters for the `whoami` command\n\tWhoAmIParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t}\n\t// WhoAmI contains the result of an 'atlas whoami' run.\n\tWhoAmI struct {\n\t\tOrg string `json:\"Org,omitempty\"`\n\t}\n\t// Version contains the result of an 'atlas version' run.\n\tVersion struct {\n\t\tVersion string `json:\"Version\"`\n\t\tSHA     string `json:\"SHA,omitempty\"`\n\t\tCanary  bool   `json:\"Canary,omitempty\"`\n\t}\n\t// VarArgs is a map of variables for the command.\n\tVarArgs interface {\n\t\t// AsArgs returns the variables as arguments.\n\t\tAsArgs() []string\n\t}\n\t// Vars2 is a map of variables for the command.\n\t// It supports multiple values for the same key (list).\n\tVars2 map[string]any\n\t// Environ is a map of environment variables.\n\tEnviron map[string]string\n\t// RunContext is an input type for describing the context of where the\n\t// command is triggered from. For example, a GitHub Action on the master branch.\n\tRunContext struct {\n\t\tRepo     string  `json:\"repo,omitempty\"`\n\t\tPath     string  `json:\"path,omitempty\"`\n\t\tBranch   string  `json:\"branch,omitempty\"`\n\t\tCommit   string  `json:\"commit,omitempty\"`\n\t\tURL      string  `json:\"url,omitempty\"`\n\t\tUsername string  `json:\"username,omitempty\"` // The username that triggered the event that initiated the command.\n\t\tUserID   string  `json:\"userID,omitempty\"`   // The user ID that triggered the event that initiated the command.\n\t\tSCMType  SCMType `json:\"scmType,omitempty\"`  // Source control management system type.\n\t}\n\t// SCMType is a type for the \"scm_type\" enum field.\n\tSCMType string\n\t// DeployRunContext is an input type for describing the context in which\n\t// `migrate-apply` and `migrate down` were used. For example, a GitHub Action with version v1.2.3\n\tDeployRunContext struct {\n\t\tTriggerType    TriggerType `json:\"triggerType,omitempty\"`\n\t\tTriggerVersion string      `json:\"triggerVersion,omitempty\"`\n\t}\n\t// TriggerType defines the type for the \"trigger_type\" enum field.\n\tTriggerType string\n\t// Vars is a map of variables for the command.\n\t//\n\t// Deprecated: Use Vars2 instead.\n\tVars map[string]string\n)\n\n// TriggerType values.\nconst (\n\tTriggerTypeCLI          TriggerType = \"CLI\"\n\tTriggerTypeKubernetes   TriggerType = \"KUBERNETES\"\n\tTriggerTypeTerraform    TriggerType = \"TERRAFORM\"\n\tTriggerTypeGithubAction TriggerType = \"GITHUB_ACTION\"\n\tTriggerTypeCircleCIOrb  TriggerType = \"CIRCLECI_ORB\"\n\tTriggerTypeGitlab       TriggerType = \"GITLAB\"\n\tTriggerTypeBitbucket    TriggerType = \"BITBUCKET\"\n\tTriggerTypeAzureDevOps  TriggerType = \"AZURE_DEVOPS\"\n)\n\n// SCMType values.\nconst (\n\tSCMTypeGithub      SCMType = \"GITHUB\"\n\tSCMTypeGitlab      SCMType = \"GITLAB\"\n\tSCMTypeBitbucket   SCMType = \"BITBUCKET\"\n\tSCMTypeAzureDevOps SCMType = \"AZURE_DEVOPS\"\n)\n\n// ExecutionOrder values.\nconst (\n\tExecOrderLinear     MigrateExecOrder = \"linear\" // Default\n\tExecOrderLinearSkip MigrateExecOrder = \"linear-skip\"\n\tExecOrderNonLinear  MigrateExecOrder = \"non-linear\"\n)\n\n// NewClient returns a new Atlas client with the given atlas-cli path.\nfunc NewClient(workingDir, execPath string) (_ *Client, err error) {\n\tif execPath == \"\" {\n\t\treturn nil, fmt.Errorf(\"execPath cannot be empty\")\n\t} else if execPath, err = exec.LookPath(execPath); err != nil {\n\t\treturn nil, fmt.Errorf(\"looking up atlas-cli: %w\", err)\n\t}\n\tif workingDir != \"\" {\n\t\t_, err := os.Stat(workingDir)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"initializing Atlas with working dir %q: %w\", workingDir, err)\n\t\t}\n\t}\n\treturn &Client{\n\t\texecPath:   execPath,\n\t\tworkingDir: workingDir,\n\t}, nil\n}\n\n// WithWorkDir creates a new client with the given working directory.\n// It is useful to run multiple commands in the multiple directories.\n//\n// Example:\n//\n//\tclient := atlasexec.NewClient(\"\", \"atlas\")\n//\terr := client.WithWorkDir(\"dir1\", func(c *atlasexec.Client) error {\n//\t  _, err := c.MigrateApply(ctx, &atlasexec.MigrateApplyParams{\n//\t  })\n//\t  return err\n//\t})\nfunc (c *Client) WithWorkDir(dir string, fn func(*Client) error) error {\n\twd := c.workingDir\n\tdefer func() { c.workingDir = wd }()\n\tc.workingDir = dir\n\treturn fn(c)\n}\n\n// SetEnv allows we override the environment variables for the atlas-cli.\n// To append new environment variables to environment from OS, use NewOSEnviron() then add new variables.\nfunc (c *Client) SetEnv(env map[string]string) error {\n\tfor k := range env {\n\t\tif _, ok := defaultEnvs[k]; ok {\n\t\t\treturn fmt.Errorf(\"atlasexec: cannot override the default environment variable %q\", k)\n\t\t}\n\t}\n\tc.env = env\n\treturn nil\n}\n\n// SetStdout specifies a writer to stream stdout to for every command.\nfunc (c *Client) SetStdout(w io.Writer) {\n\tc.stdout = w\n}\n\n// SetStderr specifies a writer to stream stderr to for every command.\nfunc (c *Client) SetStderr(w io.Writer) {\n\tc.stderr = w\n}\n\n// Login runs the 'login' command.\nfunc (c *Client) Login(ctx context.Context, params *LoginParams) error {\n\tif params.Token == \"\" {\n\t\treturn errors.New(\"token cannot be empty\")\n\t}\n\targs := []string{\"login\", \"--token\", params.Token}\n\tif params.GrantOnly {\n\t\targs = append(args, \"--grant-only\")\n\t}\n\t_, err := c.runCommand(ctx, args)\n\treturn err\n}\n\n// Logout runs the 'logout' command.\nfunc (c *Client) Logout(ctx context.Context) error {\n\t_, err := c.runCommand(ctx, []string{\"logout\"})\n\treturn err\n}\n\n// WhoAmI runs the 'whoami' command.\nfunc (c *Client) WhoAmI(ctx context.Context, params *WhoAmIParams) (*WhoAmI, error) {\n\targs := []string{\"whoami\", \"--format\", \"{{ json . }}\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\treturn firstResult(jsonDecode[WhoAmI](c.runCommand(ctx, args)))\n}\n\nvar reVersion = regexp.MustCompile(`^atlas version v(\\d+\\.\\d+.\\d+)-?([a-z0-9]*)?`)\n\n// Version runs the 'version' command.\nfunc (c *Client) Version(ctx context.Context) (*Version, error) {\n\tr, err := c.runCommand(ctx, []string{\"version\"})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tout, err := io.ReadAll(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tv := reVersion.FindSubmatch(out)\n\tif v == nil {\n\t\treturn nil, errors.New(\"unexpected output format\")\n\t}\n\tvar sha string\n\tif len(v) > 2 {\n\t\tsha = string(v[2])\n\t}\n\treturn &Version{\n\t\tVersion: string(v[1]),\n\t\tSHA:     sha,\n\t\tCanary:  strings.Contains(string(out), \"canary\"),\n\t}, nil\n}\n\n// var reVersion = regexp.MustCompile(`^atlas version v(\\d+\\.\\d+.\\d+)-?([a-z0-9]*)?`)\nfunc (v Version) String() string {\n\tvar b strings.Builder\n\tfmt.Fprintf(&b, \"atlas version v%s\", v.Version)\n\tif v.SHA != \"\" {\n\t\tfmt.Fprintf(&b, \"-%s\", v.SHA)\n\t}\n\tif v.Canary {\n\t\tb.WriteString(\"-canary\")\n\t}\n\treturn b.String()\n}\n\n// NewOSEnviron returns the current environment variables from the OS.\nfunc NewOSEnviron() Environ {\n\tenv := map[string]string{}\n\tfor _, ev := range os.Environ() {\n\t\tparts := strings.SplitN(ev, \"=\", 2)\n\t\tif len(parts) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tk := parts[0]\n\t\tv := \"\"\n\t\tif len(parts) == 2 {\n\t\t\tv = parts[1]\n\t\t}\n\t\tenv[k] = v\n\t}\n\treturn env\n}\n\n// ToSlice converts the environment variables to a slice.\nfunc (e Environ) ToSlice() []string {\n\tenv := make([]string, 0, len(e))\n\tfor k, v := range e {\n\t\tenv = append(env, k+\"=\"+v)\n\t}\n\t// Ensure the order of the envs.\n\tslices.Sort(env)\n\treturn env\n}\n\nvar defaultEnvs = map[string]string{\n\t// Disable the update notifier and upgrade suggestions.\n\t\"ATLAS_NO_UPDATE_NOTIFIER\":     \"1\",\n\t\"ATLAS_NO_UPGRADE_SUGGESTIONS\": \"1\",\n}\n\n// ErrRequireLogin is returned when a command requires the user to be logged in.\n// It exists here to be shared between the different packages that require login.\nvar ErrRequireLogin = errors.New(\"command requires 'atlas login'\")\n\n// runCommand runs the given command and returns its output.\nfunc (c *Client) runCommand(ctx context.Context, args []string) (io.Reader, error) {\n\tvar stdout, stderr bytes.Buffer\n\tcmd := c.cmd(ctx, args)\n\tcmd.Stdout = mergeWriters(&stdout, c.stdout)\n\tcmd.Stderr = mergeWriters(&stderr, c.stderr)\n\tif err := c.runErr(cmd.Run(), &stdout, &stderr); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &stdout, nil\n}\n\n// Stream is an interface for reading a stream of items.\ntype Stream[T any] interface {\n\t// Next reads the next item from the stream, making it available by calling Current.\n\t// It returns false if there are no more items and the stream is closed.\n\tNext() bool\n\t// Current returns the current item from the stream.\n\tCurrent() (T, error)\n\t// Err returns the error, if any, that occurred while reading the stream.\n\tErr() error\n}\n\n// runCommandStream runs the given command streams its output split by new-lines.\nfunc (c *Client) runCommandStream(ctx context.Context, args []string) (Stream[string], error) {\n\tcmd := c.cmd(ctx, args)\n\tvar stderr bytes.Buffer\n\tcmd.Stderr = mergeWriters(&stderr, c.stderr)\n\tout, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating stdout pipe: %w\", err)\n\t}\n\tif err = cmd.Start(); err != nil {\n\t\treturn nil, fmt.Errorf(\"starting command: %w\", err)\n\t}\n\tvar (\n\t\tscan   = bufio.NewScanner(out)\n\t\tbuf    = strings.Builder{}\n\t\tch     = make(chan string)\n\t\ts      = &stream{ch: ch}\n\t\tstdout = mergeWriters(&buf, c.stdout)\n\t)\n\tgo func() {\n\t\tdefer close(ch)\n\t\tfor scan.Scan() {\n\t\t\tstdout.Write(scan.Bytes())\n\t\t\tch <- scan.Text()\n\t\t}\n\t\ts.lock.Lock()\n\t\tdefer s.lock.Unlock()\n\t\ts.err = c.runErr(cmd.Wait(), &buf, &stderr)\n\t}()\n\treturn s, nil\n}\n\nfunc (c *Client) cmd(ctx context.Context, args []string) *exec.Cmd {\n\tcmd := exec.CommandContext(ctx, c.execPath, args...) //nolint:gosec\n\tcmd.Dir = c.workingDir\n\tvar env Environ\n\tif c.env == nil {\n\t\t// Initialize the environment variables from the OS.\n\t\tenv = NewOSEnviron()\n\t} else {\n\t\tenv = maps.Clone(c.env)\n\t}\n\tmaps.Copy(env, defaultEnvs)\n\tcmd.Env = env.ToSlice()\n\treturn cmd\n}\n\nfunc (c *Client) runErr(err error, stdout, stderr interface{ String() string }) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\te := strings.TrimSpace(stderr.String())\n\t// Explicit check the stderr for the login error.\n\tif e == \"Error: command requires 'atlas login'\" {\n\t\treturn ErrRequireLogin\n\t}\n\treturn &Error{\n\t\terr:    err,\n\t\tStderr: strings.TrimSpace(stderr.String()),\n\t\tStdout: strings.TrimSpace(stdout.String()),\n\t}\n}\n\ntype stream struct {\n\tch   chan string\n\tcur  string\n\terr  error\n\tlock sync.RWMutex\n}\n\n// Next advances the stream to the next item.\nfunc (s *stream) Next() bool {\n\ts.lock.RLock()\n\tif s.err != nil || s.ch == nil {\n\t\ts.lock.RUnlock()\n\t\treturn false\n\t}\n\ts.lock.RUnlock()\n\tr, ok := <-s.ch\n\tif !ok {\n\t\treturn false\n\t}\n\ts.cur = r\n\treturn true\n}\n\n// Current returns the current item from the stream.\nfunc (s *stream) Current() (string, error) {\n\ts.lock.RLock()\n\tdefer s.lock.RUnlock()\n\tif s.err != nil {\n\t\treturn \"\", s.err\n\t}\n\treturn s.cur, nil\n}\n\n// Err returns the error, if any, that occurred while reading the stream.\nfunc (s *stream) Err() error {\n\ts.lock.RLock()\n\tdefer s.lock.RUnlock()\n\treturn s.err\n}\n\nvar _ Stream[string] = (*stream)(nil)\n\nfunc mergeWriters(writers ...io.Writer) io.Writer {\n\tvar compact []io.Writer\n\tfor _, w := range writers {\n\t\tif w != nil {\n\t\t\tcompact = append(compact, w)\n\t\t}\n\t}\n\tswitch len(compact) {\n\tcase 1:\n\t\treturn compact[0]\n\tcase 0:\n\t\treturn io.Discard\n\tdefault:\n\t\treturn io.MultiWriter(compact...)\n\t}\n}\n\n// Error is an error returned by the atlasexec package,\n// when it executes the atlas-cli command.\ntype Error struct {\n\terr    error  // The underlying error.\n\tStdout string // Stdout of the command.\n\tStderr string // Stderr of the command.\n}\n\n// Error implements the error interface.\nfunc (e *Error) Error() string {\n\tif e.Stderr != \"\" {\n\t\treturn e.Stderr\n\t}\n\treturn e.Stdout\n}\n\n// ExitCode returns the exit code of the command.\n// If the error is not an exec.ExitError, it returns 1.\nfunc (e *Error) ExitCode() int {\n\tvar exitErr *exec.ExitError\n\tif errors.As(e.err, &exitErr) {\n\t\treturn exitErr.ExitCode()\n\t}\n\t// Not an exec.ExitError or nil.\n\t// Return the system default exit code.\n\treturn new(exec.ExitError).ExitCode()\n}\n\n// Unwrap returns the underlying error.\nfunc (e *Error) Unwrap() error {\n\treturn e.err\n}\n\n// TempFile creates a temporary file with the given content and extension.\nfunc TempFile(content, ext string) (string, func() error, error) {\n\tf, err := os.CreateTemp(\"\", \"atlasexec-*.\"+ext)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\tdefer f.Close()\n\t_, err = f.WriteString(content)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\treturn fmt.Sprintf(\"file://%s\", f.Name()), func() error {\n\t\treturn os.Remove(f.Name())\n\t}, nil\n}\n\n// AsArgs returns the variables as arguments.\nfunc (v Vars2) AsArgs() []string {\n\tkeys := make([]string, 0, len(v))\n\tfor k := range v {\n\t\tkeys = append(keys, k)\n\t}\n\tslices.Sort(keys)\n\tvar args []string\n\tfor _, k := range keys {\n\t\tswitch reflect.TypeOf(v[k]).Kind() {\n\t\tcase reflect.Slice, reflect.Array:\n\t\t\tev := reflect.ValueOf(v[k])\n\t\t\tfor i := range ev.Len() {\n\t\t\t\targs = append(args, \"--var\", fmt.Sprintf(\"%s=%v\", k, ev.Index(i)))\n\t\t\t}\n\t\tdefault:\n\t\t\targs = append(args, \"--var\", fmt.Sprintf(\"%s=%v\", k, v[k]))\n\t\t}\n\t}\n\treturn args\n}\n\n// AsArgs returns the variables as arguments.\nfunc (v Vars) AsArgs() []string {\n\tvar args []string\n\tfor k, v := range v {\n\t\targs = append(args, \"--var\", fmt.Sprintf(\"%s=%s\", k, v))\n\t}\n\treturn args\n}\n\nfunc stringVal(r io.Reader, err error) (string, error) {\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\ts, err := io.ReadAll(r)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(s), nil\n}\n\nfunc jsonDecode[T any](r io.Reader, err error) ([]*T, error) {\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbuf, err := io.ReadAll(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar dst []*T\n\tdec := json.NewDecoder(bytes.NewReader(buf))\n\tfor {\n\t\tvar m T\n\t\tswitch err := dec.Decode(&m); err {\n\t\tcase io.EOF:\n\t\t\treturn dst, nil\n\t\tcase nil:\n\t\t\tdst = append(dst, &m)\n\t\tdefault:\n\t\t\treturn nil, &Error{\n\t\t\t\terr:    fmt.Errorf(\"decoding JSON from stdout: %w\", err),\n\t\t\t\tStdout: string(buf),\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc jsonDecodeErr[T any](fn func([]*T, string) error) func(io.Reader, error) ([]*T, error) {\n\treturn func(r io.Reader, err error) ([]*T, error) {\n\t\tif err != nil {\n\t\t\tif cliErr := (&Error{}); errors.As(err, &cliErr) && cliErr.Stdout != \"\" {\n\t\t\t\td, err := jsonDecode[T](strings.NewReader(cliErr.Stdout), nil)\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn nil, fn(d, cliErr.Stderr)\n\t\t\t\t}\n\t\t\t\t// If the error is not a JSON, return the original error.\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\treturn jsonDecode[T](r, err)\n\t}\n}\n\n// repeatFlag repeats the flag for each value.\nfunc repeatFlag(flag string, values []string) []string {\n\tif len(values) == 0 {\n\t\treturn nil\n\t}\n\tout := make([]string, 0, len(values)*2)\n\tfor _, v := range values {\n\t\tout = append(out, flag, v)\n\t}\n\treturn out\n}\n\nfunc listString(args []string) string {\n\treturn strings.Join(args, \",\")\n}\n\nfunc firstResult[T ~[]E, E any](r T, err error) (e E, _ error) {\n\tswitch {\n\tcase err != nil:\n\t\treturn e, err\n\tcase len(r) == 1:\n\t\treturn r[0], nil\n\tdefault:\n\t\treturn e, errors.New(\"The command returned more than one result, use Slice function instead\")\n\t}\n}\n\nfunc last[A ~[]E, E any](a A) (_ E) {\n\tif l := len(a); l > 0 {\n\t\treturn a[l-1]\n\t}\n\treturn\n}\n"
  },
  {
    "path": "atlasexec/atlas_internal_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestEnv(t *testing.T) {\n\t// printenv is a simple command that prints all environment variables\n\tc, err := NewClient(t.TempDir(), \"printenv\")\n\trequire.NoError(t, err)\n\n\t// Should not be able to override the default environment variable\n\trequire.ErrorContains(t, c.SetEnv(map[string]string{\n\t\t\"FOO\":                      \"bar\",\n\t\t\"ATLAS_NO_UPDATE_NOTIFIER\": \"0\",\n\t}), \"cannot override the default environment variable\")\n\n\t// Should be able to set new environment variables\n\trequire.NoError(t, c.SetEnv(map[string]string{\n\t\t\"FOO\": \"bar\",\n\t\t\"BAZ\": \"qux\",\n\t}))\n\n\t// Invoke the command and check the environment variables\n\tv, err := c.runCommand(context.Background(), nil)\n\trequire.NoError(t, err)\n\traw, err := io.ReadAll(v)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `ATLAS_NO_UPDATE_NOTIFIER=1\nATLAS_NO_UPGRADE_SUGGESTIONS=1\nBAZ=qux\nFOO=bar\n`, string(raw))\n}\n"
  },
  {
    "path": "atlasexec/atlas_migrate.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\ntype (\n\t// MigrateApplyParams are the parameters for the `migrate apply` command.\n\tMigrateApplyParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *DeployRunContext\n\t\tDirURL    string\n\n\t\tURL             string\n\t\tRevisionsSchema string\n\t\tBaselineVersion string\n\t\tTxMode          string\n\t\tExecOrder       MigrateExecOrder\n\t\tAmount          uint64\n\t\tToVersion       string\n\t\tAllowDirty      bool\n\t\tDryRun          bool\n\t\tLockName        string\n\t}\n\t// MigrateApply contains a summary of a migration applying attempt on a database.\n\tMigrateApply struct {\n\t\tEnv\n\t\tPending []File         `json:\"Pending,omitempty\"` // Pending migration files\n\t\tApplied []*AppliedFile `json:\"Applied,omitempty\"` // Applied files\n\t\tCurrent string         `json:\"Current,omitempty\"` // Current migration version\n\t\tTarget  string         `json:\"Target,omitempty\"`  // Target migration version\n\t\tStart   time.Time\n\t\tEnd     time.Time\n\t\t// Error is set even then, if it was not caused by a statement in a migration file,\n\t\t// but by Atlas, e.g. when committing or rolling back a transaction.\n\t\tError string `json:\"Error,omitempty\"`\n\t}\n\t// MigrateApplyError is returned when an error occurred\n\t// during a migration applying attempt.\n\tMigrateApplyError struct {\n\t\tResult []*MigrateApply\n\t\tStderr string\n\t}\n\t// MigrateExecOrder define how Atlas computes and executes pending migration files to the database.\n\t// See: https://atlasgo.io/versioned/apply#execution-order\n\tMigrateExecOrder string\n\t// MigrateDownParams are the parameters for the `migrate down` command.\n\tMigrateDownParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *DeployRunContext\n\t\tDevURL    string\n\n\t\tDirURL          string\n\t\tURL             string\n\t\tRevisionsSchema string\n\t\tAmount          uint64\n\t\tToVersion       string\n\t\tToTag           string\n\n\t\t// Not yet supported\n\t\t// DryRun          bool\n\t\t// TxMode          string\n\t}\n\t// MigrateDown contains a summary of a migration down attempt on a database.\n\tMigrateDown struct {\n\t\tPlanned  []File          `json:\"Planned,omitempty\"`  // Planned migration files\n\t\tReverted []*RevertedFile `json:\"Reverted,omitempty\"` // Reverted files\n\t\tCurrent  string          `json:\"Current,omitempty\"`  // Current migration version\n\t\tTarget   string          `json:\"Target,omitempty\"`   // Target migration version\n\t\tTotal    int             `json:\"Total,omitempty\"`    // Total number of migrations to revert\n\t\tStart    time.Time\n\t\tEnd      time.Time\n\t\t// URL and Status are set only when the migration is planned or executed in the cloud.\n\t\tURL    string `json:\"URL,omitempty\"`\n\t\tStatus string `json:\"Status,omitempty\"`\n\t\t// Error is set even then, if it was not caused by a statement in a migration file,\n\t\t// but by Atlas, e.g. when committing or rolling back a transaction.\n\t\tError string `json:\"Error,omitempty\"`\n\t}\n\t// MigratePushParams are the parameters for the `migrate push` command.\n\tMigratePushParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *RunContext\n\t\tDevURL    string\n\n\t\tName        string\n\t\tTag         string\n\t\tDirURL      string\n\t\tDirFormat   string\n\t\tLockTimeout string\n\t}\n\t// MigrateLintParams are the parameters for the `migrate lint` command.\n\tMigrateLintParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *RunContext\n\t\tFormat    string\n\t\tDevURL    string\n\t\tGitBase   string\n\t\tGitDir    string\n\n\t\tDirURL string\n\t\tLatest uint64\n\t\tWriter io.Writer\n\t\tBase   string\n\t\tWeb    bool\n\t}\n\t// MigrateHashParams are the parameters for the `migrate hash` command.\n\tMigrateHashParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\n\t\tDirURL    string\n\t\tDirFormat string\n\t}\n\t// MigrateRebaseParams are the parameters for the `migrate rebase` command.\n\tMigrateRebaseParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\n\t\tDirURL string\n\t\tFiles  []string\n\t}\n\t// MigrateTestParams are the parameters for the `migrate test` command.\n\tMigrateTestParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *RunContext\n\t\tDevURL    string\n\n\t\tDirURL          string\n\t\tDirFormat       string\n\t\tRun             string\n\t\tRevisionsSchema string\n\t\tPaths           []string\n\t}\n\t// MigrateStatusParams are the parameters for the `migrate status` command.\n\tMigrateStatusParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\n\t\tDirURL          string\n\t\tURL             string\n\t\tRevisionsSchema string\n\t}\n\t// MigrateLsParams are the parameters for the `migrate ls` command.\n\tMigrateLsParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\n\t\tDirURL string\n\t\tShort  bool // -s: print only migration version (omit description and .sql suffix)\n\t\tLatest bool // -l: print only the latest migration file\n\t}\n\t// MigrateSetParams are the parameters for the `migrate set` command.\n\tMigrateSetParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\n\t\tDirURL          string\n\t\tURL             string\n\t\tRevisionsSchema string\n\t\tVersion         string\n\t}\n\t// MigrateDiffParams are the parameters for the `migrate diff` command.\n\tMigrateDiffParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\n\t\tName        string\n\t\tToURL       string\n\t\tDevURL      string\n\t\tDirURL      string\n\t\tDirFormat   string\n\t\tSchema      []string\n\t\tLockTimeout string\n\t\tFormat      string\n\t\tQualifier   string\n\t}\n\t// MigrateDiff contains the result of the `migrate diff` command.\n\tMigrateDiff struct {\n\t\tFiles []File `json:\"Files,omitempty\"` // Generated migration files\n\t\tDir   string `json:\"Dir,omitempty\"`   // Path to migration directory\n\t}\n\t// MigrateStatus contains a summary of the migration status of a database.\n\tMigrateStatus struct {\n\t\tEnv       Env         `json:\"Env,omitempty\"`       // Environment info.\n\t\tAvailable []File      `json:\"Available,omitempty\"` // Available migration files\n\t\tPending   []File      `json:\"Pending,omitempty\"`   // Pending migration files\n\t\tApplied   []*Revision `json:\"Applied,omitempty\"`   // Applied migration files\n\t\tCurrent   string      `json:\"Current,omitempty\"`   // Current migration version\n\t\tNext      string      `json:\"Next,omitempty\"`      // Next migration version\n\t\tCount     int         `json:\"Count,omitempty\"`     // Count of applied statements of the last revision\n\t\tTotal     int         `json:\"Total,omitempty\"`     // Total statements of the last migration\n\t\tStatus    string      `json:\"Status,omitempty\"`    // Status of migration (OK, PENDING)\n\t\tError     string      `json:\"Error,omitempty\"`     // Last Error that occurred\n\t\tSQL       string      `json:\"SQL,omitempty\"`       // SQL that caused the last Error\n\t}\n)\n\n// MigratePush runs the 'migrate push' command.\nfunc (c *Client) MigratePush(ctx context.Context, params *MigratePushParams) (string, error) {\n\targs := []string{\"migrate\", \"push\"}\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif params.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", params.DirURL)\n\t}\n\tif params.DirFormat != \"\" {\n\t\targs = append(args, \"--dir-format\", params.DirFormat)\n\t}\n\tif params.LockTimeout != \"\" {\n\t\targs = append(args, \"--lock-timeout\", params.LockTimeout)\n\t}\n\tif params.Context != nil {\n\t\tbuf, err := json.Marshal(params.Context)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\tif params.Name == \"\" {\n\t\treturn \"\", errors.New(\"directory name cannot be empty\")\n\t}\n\tif params.Tag != \"\" {\n\t\targs = append(args, fmt.Sprintf(\"%s:%s\", params.Name, params.Tag))\n\t} else {\n\t\targs = append(args, params.Name)\n\t}\n\tresp, err := stringVal(c.runCommand(ctx, args))\n\treturn strings.TrimSpace(resp), err\n}\n\n// MigrateApply runs the 'migrate apply' command.\nfunc (c *Client) MigrateApply(ctx context.Context, params *MigrateApplyParams) (*MigrateApply, error) {\n\treturn firstResult(c.MigrateApplySlice(ctx, params))\n}\n\n// MigrateApplySlice runs the 'migrate apply' command for multiple targets.\nfunc (c *Client) MigrateApplySlice(ctx context.Context, params *MigrateApplyParams) ([]*MigrateApply, error) {\n\targs := []string{\"migrate\", \"apply\", \"--format\", \"{{ json . }}\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Context != nil {\n\t\tbuf, err := json.Marshal(params.Context)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t}\n\tif params.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", params.DirURL)\n\t}\n\tif params.AllowDirty {\n\t\targs = append(args, \"--allow-dirty\")\n\t}\n\tif params.DryRun {\n\t\targs = append(args, \"--dry-run\")\n\t}\n\tif params.RevisionsSchema != \"\" {\n\t\targs = append(args, \"--revisions-schema\", params.RevisionsSchema)\n\t}\n\tif params.BaselineVersion != \"\" {\n\t\targs = append(args, \"--baseline\", params.BaselineVersion)\n\t}\n\tif params.TxMode != \"\" {\n\t\targs = append(args, \"--tx-mode\", params.TxMode)\n\t}\n\tif params.ExecOrder != \"\" {\n\t\targs = append(args, \"--exec-order\", string(params.ExecOrder))\n\t}\n\tif params.ToVersion != \"\" {\n\t\targs = append(args, \"--to-version\", params.ToVersion)\n\t}\n\tif params.Amount > 0 {\n\t\targs = append(args, strconv.FormatUint(params.Amount, 10))\n\t}\n\tif params.LockName != \"\" {\n\t\targs = append(args, \"--lock-name\", params.LockName)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\treturn jsonDecodeErr(newMigrateApplyError)(c.runCommand(ctx, args))\n}\n\n// MigrateDown runs the 'migrate down' command.\nfunc (c *Client) MigrateDown(ctx context.Context, params *MigrateDownParams) (*MigrateDown, error) {\n\targs := []string{\"migrate\", \"down\", \"--format\", \"{{ json . }}\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif params.Context != nil {\n\t\tbuf, err := json.Marshal(params.Context)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t}\n\tif params.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", params.DirURL)\n\t}\n\tif params.RevisionsSchema != \"\" {\n\t\targs = append(args, \"--revisions-schema\", params.RevisionsSchema)\n\t}\n\tif params.ToVersion != \"\" {\n\t\targs = append(args, \"--to-version\", params.ToVersion)\n\t}\n\tif params.ToTag != \"\" {\n\t\targs = append(args, \"--to-tag\", params.ToTag)\n\t}\n\tif params.Amount > 0 {\n\t\targs = append(args, strconv.FormatUint(params.Amount, 10))\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\tr, err := c.runCommand(ctx, args)\n\tif cliErr := (&Error{}); errors.As(err, &cliErr) && cliErr.Stderr == \"\" {\n\t\tr = strings.NewReader(cliErr.Stdout)\n\t\terr = nil\n\t}\n\t// NOTE: This command only support one result.\n\treturn firstResult(jsonDecode[MigrateDown](r, err))\n}\n\n// MigrateTest runs the 'migrate test' command.\nfunc (c *Client) MigrateTest(ctx context.Context, params *MigrateTestParams) (string, error) {\n\targs := []string{\"migrate\", \"test\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", params.DirURL)\n\t}\n\tif params.DirFormat != \"\" {\n\t\targs = append(args, \"--dir-format\", params.DirFormat)\n\t}\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif params.Context != nil {\n\t\tbuf, err := json.Marshal(params.Context)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\tif params.RevisionsSchema != \"\" {\n\t\targs = append(args, \"--revisions-schema\", params.RevisionsSchema)\n\t}\n\tif params.Run != \"\" {\n\t\targs = append(args, \"--run\", params.Run)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\tif len(params.Paths) > 0 {\n\t\targs = append(args, params.Paths...)\n\t}\n\treturn stringVal(c.runCommand(ctx, args))\n}\n\n// MigrateStatus runs the 'migrate status' command.\nfunc (c *Client) MigrateStatus(ctx context.Context, params *MigrateStatusParams) (*MigrateStatus, error) {\n\targs := []string{\"migrate\", \"status\", \"--format\", \"{{ json . }}\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t}\n\tif params.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", params.DirURL)\n\t}\n\tif params.RevisionsSchema != \"\" {\n\t\targs = append(args, \"--revisions-schema\", params.RevisionsSchema)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// NOTE: This command only support one result.\n\treturn firstResult(jsonDecode[MigrateStatus](c.runCommand(ctx, args)))\n}\n\n// MigrateLs runs the 'migrate ls' command and returns the listed migration file names (or versions when Short is true), one per line.\nfunc (c *Client) MigrateLs(ctx context.Context, params *MigrateLsParams) (string, error) {\n\targs := []string{\"migrate\", \"ls\"}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", params.DirURL)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\tif params.Short {\n\t\targs = append(args, \"--short\")\n\t}\n\tif params.Latest {\n\t\targs = append(args, \"--latest\")\n\t}\n\treturn stringVal(c.runCommand(ctx, args))\n}\n\n// MigrateSet runs the 'migrate set' command.\nfunc (c *Client) MigrateSet(ctx context.Context, params *MigrateSetParams) error {\n\targs := []string{\"migrate\", \"set\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t}\n\tif params.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", params.DirURL)\n\t}\n\tif params.RevisionsSchema != \"\" {\n\t\targs = append(args, \"--revisions-schema\", params.RevisionsSchema)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\tif params.Version != \"\" {\n\t\targs = append(args, params.Version)\n\t}\n\t_, err := c.runCommand(ctx, args)\n\treturn err\n}\n\n// MigrateDiff runs the 'migrate diff --dry-run' command and returns the generated migration files without changing the filesystem.\n// Requires atlas CLI to be logged in to the cloud.\nfunc (c *Client) MigrateDiff(ctx context.Context, params *MigrateDiffParams) (*MigrateDiff, error) {\n\targs := []string{\"migrate\", \"diff\", \"--dry-run\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.ToURL != \"\" {\n\t\targs = append(args, \"--to\", params.ToURL)\n\t}\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif params.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", params.DirURL)\n\t}\n\tif params.DirFormat != \"\" {\n\t\targs = append(args, \"--dir-format\", params.DirFormat)\n\t}\n\tif params.LockTimeout != \"\" {\n\t\targs = append(args, \"--lock-timeout\", params.LockTimeout)\n\t}\n\tif params.Qualifier != \"\" {\n\t\targs = append(args, \"--qualifier\", params.Qualifier)\n\t}\n\tif len(params.Schema) > 0 {\n\t\targs = append(args, \"--schema\", strings.Join(params.Schema, \",\"))\n\t}\n\tif params.Format != \"\" {\n\t\targs = append(args, \"--format\", params.Format)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\tif params.Name != \"\" {\n\t\targs = append(args, params.Name)\n\t}\n\tv, err := jsonDecode[MigrateDiff](c.runCommand(ctx, args))\n\tvar e *Error\n\tswitch {\n\t// if jsonDecode returns an error, and stderr is empty, it means the migration is synced with the desired state.\n\tcase errors.As(err, &e) && e.Stderr == \"\":\n\t\treturn &MigrateDiff{}, nil\n\tcase err != nil:\n\t\treturn nil, err\n\t}\n\treturn firstResult(v, nil)\n}\n\n// MigrateLint runs the 'migrate lint' command.\nfunc (c *Client) MigrateLint(ctx context.Context, params *MigrateLintParams) (*SummaryReport, error) {\n\tif params.Writer != nil || params.Web {\n\t\treturn nil, errors.New(\"atlasexec: Writer or Web reporting are not supported with MigrateLint, use MigrateLintError\")\n\t}\n\targs, err := params.AsArgs()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tr, err := c.runCommand(ctx, args)\n\tif cliErr := (&Error{}); errors.As(err, &cliErr) && cliErr.Stderr == \"\" {\n\t\tr = strings.NewReader(cliErr.Stdout)\n\t\terr = nil\n\t}\n\t// NOTE: This command only support one result.\n\treturn firstResult(jsonDecode[SummaryReport](r, err))\n}\n\n// MigrateHash runs the 'migrate hash' command.\nfunc (c *Client) MigrateHash(ctx context.Context, params *MigrateHashParams) error {\n\targs := []string{\"migrate\", \"hash\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\tif params.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", params.DirURL)\n\t}\n\tif params.DirFormat != \"\" {\n\t\targs = append(args, \"--dir-format\", params.DirFormat)\n\t}\n\t_, err := c.runCommand(ctx, args)\n\treturn err\n}\n\n// MigrateRebase runs the 'migrate rebase' command.\nfunc (c *Client) MigrateRebase(ctx context.Context, params *MigrateRebaseParams) error {\n\targs := []string{\"migrate\", \"rebase\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\tif params.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", params.DirURL)\n\t}\n\targs = append(args, params.Files...)\n\t_, err := c.runCommand(ctx, args)\n\treturn err\n}\n\n// MigrateLintError runs the 'migrate lint' command, the output is written to params.Writer and reports\n// if an error occurred. If the error is a setup error, a Error is returned. If the error is a lint error,\n// LintErr is returned.\nfunc (c *Client) MigrateLintError(ctx context.Context, params *MigrateLintParams) error {\n\targs, err := params.AsArgs()\n\tif err != nil {\n\t\treturn err\n\t}\n\tr, err := c.runCommand(ctx, args)\n\tvar (\n\t\tcliErr *Error\n\t\tisCLI  = errors.As(err, &cliErr)\n\t)\n\t// Setup errors.\n\tif isCLI && cliErr.Stderr != \"\" {\n\t\treturn cliErr\n\t}\n\t// Lint errors.\n\tif isCLI && cliErr.Stdout != \"\" {\n\t\terr = ErrLint\n\t\tr = strings.NewReader(cliErr.Stdout)\n\t}\n\t// Unknown errors.\n\tif err != nil && !isCLI {\n\t\treturn err\n\t}\n\tif params.Writer != nil && r != nil {\n\t\tif _, ioErr := io.Copy(params.Writer, r); ioErr != nil {\n\t\t\terr = errors.Join(err, ioErr)\n\t\t}\n\t}\n\treturn err\n}\n\n// AsArgs returns the parameters as arguments.\nfunc (p *MigrateLintParams) AsArgs() ([]string, error) {\n\targs := []string{\"migrate\", \"lint\"}\n\tif p.Web {\n\t\targs = append(args, \"-w\")\n\t}\n\tif p.Context != nil {\n\t\tbuf, err := json.Marshal(p.Context)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\tif p.Env != \"\" {\n\t\targs = append(args, \"--env\", p.Env)\n\t}\n\tif p.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", p.ConfigURL)\n\t}\n\tif p.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", p.DevURL)\n\t}\n\tif p.DirURL != \"\" {\n\t\targs = append(args, \"--dir\", p.DirURL)\n\t}\n\tif p.Base != \"\" {\n\t\targs = append(args, \"--base\", p.Base)\n\t}\n\tif p.Latest > 0 {\n\t\targs = append(args, \"--latest\", strconv.FormatUint(p.Latest, 10))\n\t}\n\tif p.GitBase != \"\" {\n\t\targs = append(args, \"--git-base\", p.GitBase)\n\t}\n\tif p.GitDir != \"\" {\n\t\targs = append(args, \"--git-dir\", p.GitDir)\n\t}\n\tif p.Vars != nil {\n\t\targs = append(args, p.Vars.AsArgs()...)\n\t}\n\tformat := \"{{ json . }}\"\n\tif p.Format != \"\" {\n\t\tformat = p.Format\n\t}\n\targs = append(args, \"--format\", format)\n\treturn args, nil\n}\n\n// Summary of the migration attempt.\nfunc (a *MigrateApply) Summary(ident string) string {\n\tvar (\n\t\tpassedC, failedC int\n\t\tpassedS, failedS int\n\t\tpassedF, failedF int\n\t\tlines            = make([]string, 0, 3)\n\t)\n\tfor _, f := range a.Applied {\n\t\t// For each check file, count the\n\t\t// number of failed assertions.\n\t\tfor _, cf := range f.Checks {\n\t\t\tfor _, s := range cf.Stmts {\n\t\t\t\tif s.Error != nil {\n\t\t\t\t\tfailedC++\n\t\t\t\t} else {\n\t\t\t\t\tpassedC++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tpassedS += len(f.Applied)\n\t\tif f.Error != nil {\n\t\t\tfailedF++\n\t\t\t// Last statement failed (not an assertion).\n\t\t\tif len(f.Checks) == 0 || f.Checks[len(f.Checks)-1].Error == nil {\n\t\t\t\tpassedS--\n\t\t\t\tfailedS++\n\t\t\t}\n\t\t} else {\n\t\t\tpassedF++\n\t\t}\n\t}\n\t// Execution time.\n\tlines = append(lines, a.End.Sub(a.Start).String())\n\t// Executed files.\n\tswitch {\n\tcase passedF > 0 && failedF > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d migration%s ok, %d with errors\", passedF, plural(passedF), failedF))\n\tcase passedF > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d migration%s\", passedF, plural(passedF)))\n\tcase failedF > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d migration%s with errors\", failedF, plural(failedF)))\n\t}\n\t// Executed checks.\n\tswitch {\n\tcase passedC > 0 && failedC > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d check%s ok, %d failure%s\", passedC, plural(passedC), failedC, plural(failedC)))\n\tcase passedC > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d check%s\", passedC, plural(passedC)))\n\tcase failedC > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d check error%s\", failedC, plural(failedC)))\n\t}\n\t// Executed statements.\n\tswitch {\n\tcase passedS > 0 && failedS > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d sql statement%s ok, %d with errors\", passedS, plural(passedS), failedS))\n\tcase passedS > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d sql statement%s\", passedS, plural(passedS)))\n\tcase failedS > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d sql statement%s with errors\", failedS, plural(failedS)))\n\t}\n\tvar b strings.Builder\n\tfor i, l := range lines {\n\t\tb.WriteString(\"-\")\n\t\tb.WriteByte(' ')\n\t\tb.WriteString(fmt.Sprintf(\"**%s**\", l))\n\t\tif i < len(lines)-1 {\n\t\t\tb.WriteByte('\\n')\n\t\t\tb.WriteString(ident)\n\t\t}\n\t}\n\treturn b.String()\n}\n\nvar (\n\t// ErrLint is returned when the 'migrate lint' finds a diagnostic that is configured to\n\t// be reported as an error, such as destructive changes by default.\n\tErrLint = errors.New(\"lint error\")\n\t// Deprecated: Use ErrLint instead.\n\tLintErr = ErrLint\n)\n\n// LatestVersion returns the latest version of the migration directory.\nfunc (r MigrateStatus) LatestVersion() string {\n\tif l := len(r.Available); l > 0 {\n\t\treturn r.Available[l-1].Version\n\t}\n\treturn \"\"\n}\n\n// Amount returns the number of migrations need to apply\n// for the given version.\n//\n// The second return value is true if the version is found\n// and the database is up-to-date.\n//\n// If the version is not found, it returns 0 and the second\n// return value is false.\nfunc (r MigrateStatus) Amount(version string) (amount uint64, ok bool) {\n\tif version == \"\" {\n\t\tamount := uint64(len(r.Pending))\n\t\treturn amount, amount == 0\n\t}\n\tif r.Current == version {\n\t\treturn amount, true\n\t}\n\tfor idx, v := range r.Pending {\n\t\tif v.Version == version {\n\t\t\tamount = uint64(idx + 1) //nolint:gosec //G115: Safe conversion as idx is from range\n\t\t\tbreak\n\t\t}\n\t}\n\treturn amount, false\n}\n\nfunc newMigrateApplyError(r []*MigrateApply, stderr string) error {\n\treturn &MigrateApplyError{Result: r, Stderr: stderr}\n}\n\n// Error implements the error interface.\nfunc (e *MigrateApplyError) Error() string {\n\tvar errs []string\n\tfor _, r := range e.Result {\n\t\tif r.Error != \"\" {\n\t\t\terrs = append(errs, r.Error)\n\t\t}\n\t}\n\tif e.Stderr != \"\" {\n\t\terrs = append(errs, e.Stderr)\n\t}\n\treturn strings.Join(errs, \"\\n\")\n}\n\nfunc plural(n int) (s string) {\n\tif n > 1 {\n\t\ts += \"s\"\n\t}\n\treturn\n}\n"
  },
  {
    "path": "atlasexec/atlas_migrate_example_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"ariga.io/atlas/atlasexec\"\n)\n\nfunc ExampleClient_MigrateApply() {\n\t// Define the execution context, supplying a migration directory\n\t// and potentially an `atlas.hcl` configuration file using `atlasexec.WithHCL`.\n\tworkdir, err := atlasexec.NewWorkingDir(\n\t\tatlasexec.WithMigrations(\n\t\t\tos.DirFS(\"./migrations\"),\n\t\t),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to load working directory: %v\", err)\n\t}\n\t// atlasexec works on a temporary directory, so we need to close it\n\tdefer workdir.Close()\n\n\t// Initialize the client.\n\tclient, err := atlasexec.NewClient(workdir.Path(), \"atlas\")\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to initialize client: %v\", err)\n\t}\n\t// Run `atlas migrate apply` on a SQLite database under /tmp.\n\tres, err := client.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{\n\t\tURL: \"sqlite:///tmp/demo.db?_fk=1&cache=shared\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to apply migrations: %v\", err)\n\t}\n\tfmt.Printf(\"Applied %d migrations\\n\", len(res.Applied))\n}\n\nfunc ExampleClient_MigrateSet() {\n\t// Define the execution context, supplying a migration directory\n\t// and potentially an `atlas.hcl` configuration file using `atlasexec.WithHCL`.\n\tworkdir, err := atlasexec.NewWorkingDir(\n\t\tatlasexec.WithMigrations(\n\t\t\tos.DirFS(\"./migrations\"),\n\t\t),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to load working directory: %v\", err)\n\t}\n\t// atlasexec works on a temporary directory, so we need to close it\n\tdefer workdir.Close()\n\n\t// Initialize the client.\n\tclient, err := atlasexec.NewClient(workdir.Path(), \"atlas\")\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to initialize client: %v\", err)\n\t}\n\t// Run `atlas migrate set` to mark migrations as applied up to version \"3\".\n\terr = client.MigrateSet(context.Background(), &atlasexec.MigrateSetParams{\n\t\tURL:     \"sqlite:///tmp/demo.db?_fk=1&cache=shared\",\n\t\tVersion: \"3\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to set migrations: %v\", err)\n\t}\n\tfmt.Println(\"Migration version set successfully\")\n}\n"
  },
  {
    "path": "atlasexec/atlas_migrate_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/atlasexec\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestMigrate_Status(t *testing.T) {\n\ttype args struct {\n\t\tctx  context.Context\n\t\tdata *atlasexec.MigrateStatusParams\n\t}\n\ttests := []struct {\n\t\tname        string\n\t\targs        args\n\t\twantCurrent string\n\t\twantNext    string\n\t\twantErr     bool\n\t}{\n\t\t{\n\t\t\targs: args{\n\t\t\t\tctx: context.Background(),\n\t\t\t\tdata: &atlasexec.MigrateStatusParams{\n\t\t\t\t\tDirURL: \"file://testdata/migrations\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCurrent: \"No migration applied yet\",\n\t\t\twantNext:    \"20230727105553\",\n\t\t},\n\t}\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(wd, \"atlas\")\n\trequire.NoError(t, err)\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttt.args.data.URL = sqlitedb(t, \"\")\n\t\t\tgot, err := c.MigrateStatus(tt.args.ctx, tt.args.data)\n\t\t\tif (err != nil) != tt.wantErr {\n\t\t\t\tt.Errorf(\"migrateStatus() error = %v, wantErr %v\", err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.Equal(t, tt.wantCurrent, got.Current)\n\t\t\trequire.Equal(t, tt.wantNext, got.Next)\n\t\t})\n\t}\n}\n\nfunc TestMigrate_Apply(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname   string\n\t\tparams *atlasexec.MigrateApplyParams\n\t\targs   string\n\t\tstdout string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.MigrateApplyParams{},\n\t\t\targs:   \"migrate apply --format {{ json . }}\",\n\t\t\tstdout: `{\"Driver\":\"mysql\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with env\",\n\t\t\tparams: &atlasexec.MigrateApplyParams{\n\t\t\t\tEnv: \"test\",\n\t\t\t},\n\t\t\targs:   \"migrate apply --format {{ json . }} --env test\",\n\t\t\tstdout: `{\"Driver\":\"mysql\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with url\",\n\t\t\tparams: &atlasexec.MigrateApplyParams{\n\t\t\t\tURL: \"sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\t},\n\t\t\targs:   \"migrate apply --format {{ json . }} --url sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\tstdout: `{\"Driver\":\"mysql\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with exec order\",\n\t\t\tparams: &atlasexec.MigrateApplyParams{\n\t\t\t\tExecOrder: atlasexec.ExecOrderLinear,\n\t\t\t},\n\t\t\targs:   \"migrate apply --format {{ json . }} --exec-order linear\",\n\t\t\tstdout: `{\"Driver\":\"mysql\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with lock name\",\n\t\t\tparams: &atlasexec.MigrateApplyParams{\n\t\t\t\tLockName: \"custom_lock\",\n\t\t\t},\n\t\t\targs:   \"migrate apply --format {{ json . }} --lock-name custom_lock\",\n\t\t\tstdout: `{\"Driver\":\"mysql\"}`,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", tt.stdout)\n\t\t\tresult, err := c.MigrateApply(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, result)\n\t\t\trequire.Equal(t, \"mysql\", result.Driver)\n\t\t})\n\t}\n}\n\nfunc TestMigrate_Ls(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname   string\n\t\tparams *atlasexec.MigrateLsParams\n\t\targs   string\n\t\tstdout string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.MigrateLsParams{},\n\t\t\targs:   \"migrate ls\",\n\t\t\tstdout: \"\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"with dir\",\n\t\t\tparams: &atlasexec.MigrateLsParams{\n\t\t\t\tDirURL: \"file://migrations\",\n\t\t\t},\n\t\t\targs:   \"migrate ls --dir file://migrations\",\n\t\t\tstdout: \"\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"with short\",\n\t\t\tparams: &atlasexec.MigrateLsParams{\n\t\t\t\tShort: true,\n\t\t\t},\n\t\t\targs:   \"migrate ls --short\",\n\t\t\tstdout: \"\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"with latest\",\n\t\t\tparams: &atlasexec.MigrateLsParams{\n\t\t\t\tLatest: true,\n\t\t\t},\n\t\t\targs:   \"migrate ls --latest\",\n\t\t\tstdout: \"\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"with short and latest\",\n\t\t\tparams: &atlasexec.MigrateLsParams{\n\t\t\t\tDirURL: \"file://migrations\",\n\t\t\t\tShort:  true,\n\t\t\t\tLatest: true,\n\t\t\t},\n\t\t\targs:   \"migrate ls --dir file://migrations --short --latest\",\n\t\t\tstdout: \"20230727105615\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"with config and env\",\n\t\t\tparams: &atlasexec.MigrateLsParams{\n\t\t\t\tConfigURL: \"file://atlas.hcl\",\n\t\t\t\tEnv:       \"dev\",\n\t\t\t},\n\t\t\targs:   \"migrate ls --config file://atlas.hcl --env dev\",\n\t\t\tstdout: \"\\n\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", tt.stdout)\n\t\t\tgot, err := c.MigrateLs(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.stdout, got)\n\t\t})\n\t}\n}\n\nfunc TestMigrate_Ls_Integration(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(wd, \"atlas\")\n\trequire.NoError(t, err)\n\n\tdirURL := \"file://testdata/migrations\"\n\tout, err := c.MigrateLs(context.Background(), &atlasexec.MigrateLsParams{DirURL: dirURL})\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), \"unknown\") || strings.Contains(err.Error(), \"unknown command\") {\n\t\t\tt.Skip(\"atlas binary does not support 'migrate ls' (e.g. OSS build)\")\n\t\t}\n\t\trequire.NoError(t, err)\n\t}\n\tlines := strings.Split(strings.TrimSpace(out), \"\\n\")\n\trequire.GreaterOrEqual(t, len(lines), 2)\n\trequire.Contains(t, out, \"20230727105553_init.sql\")\n\trequire.Contains(t, out, \"20230727105615_t2.sql\")\n\n\toutShort, err := c.MigrateLs(context.Background(), &atlasexec.MigrateLsParams{DirURL: dirURL, Short: true})\n\tif err != nil && strings.Contains(err.Error(), \"unknown flag\") {\n\t\tt.Skip(\"atlas binary does not support --short/--latest (use enterprise or newer build)\")\n\t}\n\trequire.NoError(t, err)\n\trequire.Contains(t, outShort, \"20230727105553\")\n\trequire.Contains(t, outShort, \"20230727105615\")\n\trequire.NotContains(t, outShort, \".sql\")\n\n\toutLatest, err := c.MigrateLs(context.Background(), &atlasexec.MigrateLsParams{DirURL: dirURL, Latest: true})\n\trequire.NoError(t, err)\n\trequire.Equal(t, 1, len(strings.Split(strings.TrimSpace(outLatest), \"\\n\")))\n\trequire.Contains(t, outLatest, \"20230926085734_destructive-change.sql\")\n}\n\nfunc TestMigrate_Set(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname   string\n\t\tparams *atlasexec.MigrateSetParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.MigrateSetParams{},\n\t\t\targs:   \"migrate set\",\n\t\t},\n\t\t{\n\t\t\tname: \"with env\",\n\t\t\tparams: &atlasexec.MigrateSetParams{\n\t\t\t\tEnv: \"test\",\n\t\t\t},\n\t\t\targs: \"migrate set --env test\",\n\t\t},\n\t\t{\n\t\t\tname: \"with url\",\n\t\t\tparams: &atlasexec.MigrateSetParams{\n\t\t\t\tURL: \"sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\t},\n\t\t\targs: \"migrate set --url sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t},\n\t\t{\n\t\t\tname: \"with dir\",\n\t\t\tparams: &atlasexec.MigrateSetParams{\n\t\t\t\tDirURL: \"file://migrations\",\n\t\t\t},\n\t\t\targs: \"migrate set --dir file://migrations\",\n\t\t},\n\t\t{\n\t\t\tname: \"with revisions-schema\",\n\t\t\tparams: &atlasexec.MigrateSetParams{\n\t\t\t\tRevisionsSchema: \"my_revisions\",\n\t\t\t},\n\t\t\targs: \"migrate set --revisions-schema my_revisions\",\n\t\t},\n\t\t{\n\t\t\tname: \"with version\",\n\t\t\tparams: &atlasexec.MigrateSetParams{\n\t\t\t\tVersion: \"3\",\n\t\t\t},\n\t\t\targs: \"migrate set 3\",\n\t\t},\n\t\t{\n\t\t\tname: \"with all params\",\n\t\t\tparams: &atlasexec.MigrateSetParams{\n\t\t\t\tURL:             \"sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\t\tDirURL:          \"file://migrations\",\n\t\t\t\tRevisionsSchema: \"my_revisions\",\n\t\t\t\tVersion:         \"1.2.4\",\n\t\t\t},\n\t\t\targs: \"migrate set --url sqlite://file?_fk=1&cache=shared&mode=memory --dir file://migrations --revisions-schema my_revisions 1.2.4\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", \"ok\")\n\t\t\terr := c.MigrateSet(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestMigrate_Down(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname   string\n\t\tparams *atlasexec.MigrateDownParams\n\t\targs   string\n\t\tstdout string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.MigrateDownParams{},\n\t\t\targs:   \"migrate down --format {{ json . }}\",\n\t\t\tstdout: `{\"Status\":\"Pending\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with env\",\n\t\t\tparams: &atlasexec.MigrateDownParams{\n\t\t\t\tEnv: \"test\",\n\t\t\t},\n\t\t\targs:   \"migrate down --format {{ json . }} --env test\",\n\t\t\tstdout: `{\"Status\":\"Pending\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with url\",\n\t\t\tparams: &atlasexec.MigrateDownParams{\n\t\t\t\tURL: \"sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\t},\n\t\t\targs:   \"migrate down --format {{ json . }} --url sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\tstdout: `{\"Status\":\"Pending\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with target version\",\n\t\t\tparams: &atlasexec.MigrateDownParams{\n\t\t\t\tToVersion: \"12345\",\n\t\t\t},\n\t\t\targs:   \"migrate down --format {{ json . }} --to-version 12345\",\n\t\t\tstdout: `{\"Status\":\"Pending\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with tag version\",\n\t\t\tparams: &atlasexec.MigrateDownParams{\n\t\t\t\tToTag: \"12345\",\n\t\t\t},\n\t\t\targs:   \"migrate down --format {{ json . }} --to-tag 12345\",\n\t\t\tstdout: `{\"Status\":\"Pending\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with amount\",\n\t\t\tparams: &atlasexec.MigrateDownParams{\n\t\t\t\tAmount: 10,\n\t\t\t},\n\t\t\targs:   \"migrate down --format {{ json . }} 10\",\n\t\t\tstdout: `{\"Status\":\"Pending\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"dev-url\",\n\t\t\tparams: &atlasexec.MigrateDownParams{\n\t\t\t\tDevURL: \"url\",\n\t\t\t},\n\t\t\targs:   \"migrate down --format {{ json . }} --dev-url url\",\n\t\t\tstdout: `{\"Status\":\"Pending\"}`,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", tt.stdout)\n\t\t\tresult, err := c.MigrateDown(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, result)\n\t\t\trequire.Equal(t, \"Pending\", result.Status)\n\t\t})\n\t}\n}\n\nfunc TestMigrate_Test(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname   string\n\t\tparams *atlasexec.MigrateTestParams\n\t\targs   string\n\t\tstdout string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.MigrateTestParams{},\n\t\t\targs:   \"migrate test\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with env\",\n\t\t\tparams: &atlasexec.MigrateTestParams{\n\t\t\t\tEnv: \"test\",\n\t\t\t},\n\t\t\targs:   \"migrate test --env test\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with config\",\n\t\t\tparams: &atlasexec.MigrateTestParams{\n\t\t\t\tConfigURL: \"file://config.hcl\",\n\t\t\t},\n\t\t\targs:   \"migrate test --config file://config.hcl\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with dev-url\",\n\t\t\tparams: &atlasexec.MigrateTestParams{\n\t\t\t\tDevURL: \"sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\t},\n\t\t\targs:   \"migrate test --dev-url sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with run\",\n\t\t\tparams: &atlasexec.MigrateTestParams{\n\t\t\t\tRun: \"example\",\n\t\t\t},\n\t\t\targs:   \"migrate test --run example\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with run and paths\",\n\t\t\tparams: &atlasexec.MigrateTestParams{\n\t\t\t\tRun:   \"example\",\n\t\t\t\tPaths: []string{\"./foo\", \"./bar\"},\n\t\t\t},\n\t\t\targs:   \"migrate test --run example ./foo ./bar\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with revisions-schema\",\n\t\t\tparams: &atlasexec.MigrateTestParams{\n\t\t\t\tRevisionsSchema: \"schema\",\n\t\t\t},\n\t\t\targs:   \"migrate test --revisions-schema schema\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with run context\",\n\t\t\tparams: &atlasexec.MigrateTestParams{\n\t\t\t\tContext: &atlasexec.RunContext{\n\t\t\t\t\tRepo: \"testing-repo\",\n\t\t\t\t},\n\t\t\t},\n\t\t\targs:   \"migrate test --context {\\\"repo\\\":\\\"testing-repo\\\"}\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", tt.stdout)\n\t\t\tresult, err := c.MigrateTest(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.stdout, result)\n\t\t})\n\t}\n}\n\nfunc TestAtlasMigrate_ApplyBroken(t *testing.T) {\n\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\trequire.NoError(t, err)\n\tgot, err := c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{\n\t\tURL:    \"sqlite://?mode=memory\",\n\t\tDirURL: \"file://testdata/broken\",\n\t})\n\trequire.ErrorContains(t, err, `sql/migrate: executing statement \"broken;\" from version \"20231029112426\": near \"broken\": syntax error`)\n\trequire.Nil(t, got)\n\treport, ok := err.(*atlasexec.MigrateApplyError)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"20231029112426\", report.Result[0].Target)\n\trequire.Equal(t, \"sql/migrate: executing statement \\\"broken;\\\" from version \\\"20231029112426\\\": near \\\"broken\\\": syntax error\", report.Error())\n\trequire.Len(t, report.Result[0].Applied, 1)\n\trequire.Equal(t, &struct {\n\t\tStmt, Text string\n\t}{\n\t\tStmt: \"broken;\",\n\t\tText: \"near \\\"broken\\\": syntax error\",\n\t}, report.Result[0].Applied[0].Error)\n}\n\nfunc TestMigrateApplyError_Error(t *testing.T) {\n\tt.Run(\"single result error only\", func(t *testing.T) {\n\t\te := &atlasexec.MigrateApplyError{\n\t\t\tResult: []*atlasexec.MigrateApply{\n\t\t\t\t{Error: \"sql/migrate: execution failed\"},\n\t\t\t},\n\t\t}\n\t\trequire.Equal(t, \"sql/migrate: execution failed\", e.Error())\n\t})\n\n\tt.Run(\"stderr only\", func(t *testing.T) {\n\t\te := &atlasexec.MigrateApplyError{\n\t\t\tStderr: \"Error: unable to acquire lock\",\n\t\t}\n\t\trequire.Equal(t, \"Error: unable to acquire lock\", e.Error())\n\t})\n\n\tt.Run(\"single result error and stderr\", func(t *testing.T) {\n\t\te := &atlasexec.MigrateApplyError{\n\t\t\tResult: []*atlasexec.MigrateApply{\n\t\t\t\t{Error: \"sql/migrate: execution failed\"},\n\t\t\t},\n\t\t\tStderr: \"Error: unable to acquire lock\",\n\t\t}\n\t\trequire.Equal(t, \"sql/migrate: execution failed\\nError: unable to acquire lock\", e.Error())\n\t})\n\n\tt.Run(\"multiple result errors and stderr\", func(t *testing.T) {\n\t\te := &atlasexec.MigrateApplyError{\n\t\t\tResult: []*atlasexec.MigrateApply{\n\t\t\t\t{Error: \"error on target 1\"},\n\t\t\t\t{Error: \"error on target 2\"},\n\t\t\t},\n\t\t\tStderr: \"Error: unable to acquire lock\",\n\t\t}\n\t\trequire.Equal(t, \"error on target 1\\nerror on target 2\\nError: unable to acquire lock\", e.Error())\n\t})\n\n\tt.Run(\"multiple results with some having no error\", func(t *testing.T) {\n\t\te := &atlasexec.MigrateApplyError{\n\t\t\tResult: []*atlasexec.MigrateApply{\n\t\t\t\t{Error: \"\"},\n\t\t\t\t{Error: \"error on target 2\"},\n\t\t\t\t{Error: \"\"},\n\t\t\t},\n\t\t\tStderr: \"Error: unable to acquire lock\",\n\t\t}\n\t\trequire.Equal(t, \"error on target 2\\nError: unable to acquire lock\", e.Error())\n\t})\n\n\tt.Run(\"no errors at all\", func(t *testing.T) {\n\t\te := &atlasexec.MigrateApplyError{\n\t\t\tResult: []*atlasexec.MigrateApply{\n\t\t\t\t{Error: \"\"},\n\t\t\t},\n\t\t}\n\t\trequire.Equal(t, \"\", e.Error())\n\t})\n\n\tt.Run(\"nil result with stderr\", func(t *testing.T) {\n\t\te := &atlasexec.MigrateApplyError{\n\t\t\tStderr: \"Error: connection refused\",\n\t\t}\n\t\trequire.Equal(t, \"Error: connection refused\", e.Error())\n\t})\n}\n\nfunc TestAtlasMigrate_Apply(t *testing.T) {\n\tec, err := atlasexec.NewWorkingDir(\n\t\tatlasexec.WithMigrations(os.DirFS(filepath.Join(\"testdata\", \"migrations\"))),\n\t\tatlasexec.WithAtlasHCL(func(w io.Writer) error {\n\t\t\t_, err := w.Write([]byte(`\n\t\t\tvariable \"url\" {\n\t\t\t\ttype    = string\n\t\t\t\tdefault = getenv(\"DB_URL\")\n\t\t\t}\n\t\t\tenv {\n\t\t\t\tname = atlas.env\n\t\t\t\turl  = var.url\n\t\t\t\tmigration {\n\t\t\t\t\tdir = \"file://migrations\"\n\t\t\t\t}\n\t\t\t}`))\n\t\t\treturn err\n\t\t}),\n\t)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, ec.Close())\n\t})\n\tc, err := atlasexec.NewClient(ec.Path(), \"atlas\")\n\trequire.NoError(t, err)\n\tgot, err := c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{\n\t\tEnv: \"test\",\n\t})\n\trequire.ErrorContains(t, err, `required flag \"url\" not set`)\n\trequire.Nil(t, got)\n\tvar exerr *exec.ExitError\n\trequire.ErrorAs(t, err, &exerr)\n\t// Set the env var and try again\n\tos.Setenv(\"DB_URL\", \"sqlite://file?_fk=1&cache=shared&mode=memory\")\n\tgot, err = c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{\n\t\tEnv: \"test\",\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"sqlite\", got.Env.Driver)\n\trequire.Equal(t, \"file://migrations\", got.Env.Dir)\n\trequire.Equal(t, \"sqlite://file?_fk=1&cache=shared&mode=memory\", got.Env.URL.String())\n\trequire.Equal(t, \"20230926085734\", got.Target)\n\t// Add dirty changes and try again\n\tos.Setenv(\"DB_URL\", \"sqlite://test.db?_fk=1&cache=shared&mode=memory\")\n\tdrv, err := sql.Open(\"sqlite3\", \"test.db\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(\"test.db\")\n\t_, err = drv.ExecContext(context.Background(), \"create table atlas_schema_revisions(version varchar(255) not null primary key);\")\n\trequire.NoError(t, err)\n\tgot, err = c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{\n\t\tEnv:        \"test\",\n\t\tAllowDirty: true,\n\t})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"20230926085734\", got.Target)\n}\n\nfunc TestAtlasMigrate_ApplyWithRemote(t *testing.T) {\n\ttype (\n\t\tContextInput struct {\n\t\t\tTriggerType    string `json:\"triggerType,omitempty\"`\n\t\t\tTriggerVersion string `json:\"triggerVersion,omitempty\"`\n\t\t}\n\t\tgraphQLQuery struct {\n\t\t\tQuery              string          `json:\"query\"`\n\t\t\tVariables          json.RawMessage `json:\"variables\"`\n\t\t\tMigrateApplyReport struct {\n\t\t\t\tInput struct {\n\t\t\t\t\tContext *ContextInput `json:\"context,omitempty\"`\n\t\t\t\t} `json:\"input\"`\n\t\t\t}\n\t\t}\n\t)\n\ttoken := \"123456789\"\n\thandler := func(payloads *[]graphQLQuery) http.HandlerFunc {\n\t\treturn func(_ http.ResponseWriter, r *http.Request) {\n\t\t\trequire.Equal(t, \"Bearer \"+token, r.Header.Get(\"Authorization\"))\n\t\t\tvar query graphQLQuery\n\t\t\trequire.NoError(t, json.NewDecoder(r.Body).Decode(&query))\n\t\t\t*payloads = append(*payloads, query)\n\t\t}\n\t}\n\tvar payloads []graphQLQuery\n\tsrv := httptest.NewServer(handler(&payloads))\n\tt.Cleanup(srv.Close)\n\tec, err := atlasexec.NewWorkingDir(\n\t\tatlasexec.WithMigrations(os.DirFS(filepath.Join(\"testdata\", \"migrations\"))),\n\t\tatlasexec.WithAtlasHCL(func(w io.Writer) error {\n\t\t\t_, err := fmt.Fprintf(w, `\n\t\t\tenv {\n\t\t\t\tname = atlas.env\n\t\t\t\turl  = \"sqlite://file?_fk=1&cache=shared&mode=memory\"\n\t\t\t\tmigration {\n\t\t\t\t\tdir = \"atlas://test_dir\"\n\t\t\t\t}\n\t\t\t}\n\t\t\tatlas {\n\t\t\t\tcloud {\n\t\t\t\t\ttoken = %q\n\t\t\t\t\turl = %q\n\t\t\t\t}\n\t\t\t}`, token, srv.URL)\n\t\t\treturn err\n\t\t}),\n\t)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, ec.Close())\n\t})\n\tc, err := atlasexec.NewClient(ec.Path(), \"atlas\")\n\trequire.NoError(t, err)\n\tgot, err := c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{\n\t\tEnv: \"test\",\n\t})\n\trequire.NoError(t, err)\n\trequire.NotNil(t, got)\n\trequire.Len(t, payloads, 3)\n\treportPayload := payloads[2]\n\trequire.Regexp(t, \"mutation ReportMigration\", reportPayload.Query)\n\terr = json.Unmarshal(reportPayload.Variables, &reportPayload.MigrateApplyReport)\n\trequire.NoError(t, err)\n\trequire.Nil(t, reportPayload.MigrateApplyReport.Input.Context)\n\tgot, err = c.MigrateApply(context.Background(), &atlasexec.MigrateApplyParams{\n\t\tEnv:     \"test\",\n\t\tContext: &atlasexec.DeployRunContext{TriggerVersion: \"1.2.3\", TriggerType: atlasexec.TriggerTypeGithubAction},\n\t})\n\trequire.NoError(t, err)\n\trequire.NotNil(t, got)\n\trequire.Len(t, payloads, 6)\n\treportPayload = payloads[5]\n\trequire.Regexp(t, \"mutation ReportMigration\", reportPayload.Query)\n\terr = json.Unmarshal(reportPayload.Variables, &reportPayload.MigrateApplyReport)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, reportPayload.MigrateApplyReport.Input.Context)\n\trequire.Equal(t, \"GITHUB_ACTION\", reportPayload.MigrateApplyReport.Input.Context.TriggerType)\n\trequire.Equal(t, \"1.2.3\", reportPayload.MigrateApplyReport.Input.Context.TriggerVersion)\n}\n\nfunc TestAtlasMigrate_Push(t *testing.T) {\n\ttype (\n\t\tgraphQLQuery struct {\n\t\t\tQuery     string          `json:\"query\"`\n\t\t\tVariables json.RawMessage `json:\"variables\"`\n\t\t\tPushDir   *struct {\n\t\t\t\tInput struct {\n\t\t\t\t\tSlug   string `json:\"slug\"`\n\t\t\t\t\tTag    string `json:\"tag\"`\n\t\t\t\t\tDriver string `json:\"driver\"`\n\t\t\t\t\tDir    string `json:\"dir\"`\n\t\t\t\t} `json:\"input\"`\n\t\t\t}\n\t\t\tDiffSyncDir *struct {\n\t\t\t\tInput struct {\n\t\t\t\t\tSlug    string                `json:\"slug\"`\n\t\t\t\t\tDriver  string                `json:\"driver\"`\n\t\t\t\t\tDir     string                `json:\"dir\"`\n\t\t\t\t\tAdd     string                `json:\"add\"`\n\t\t\t\t\tDelete  []string              `json:\"delete\"`\n\t\t\t\t\tContext *atlasexec.RunContext `json:\"context\"`\n\t\t\t\t} `json:\"input\"`\n\t\t\t}\n\t\t}\n\t\thttpTest struct {\n\t\t\tpayloads []graphQLQuery\n\t\t\tsrv      *httptest.Server\n\t\t}\n\t)\n\ttoken := \"123456789\"\n\tnewHTTPTest := func() (*httpTest, string) {\n\t\ttt := &httpTest{}\n\t\thandler := func() http.HandlerFunc {\n\t\t\treturn func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\trequire.Equal(t, \"Bearer \"+token, r.Header.Get(\"Authorization\"))\n\t\t\t\tvar query graphQLQuery\n\t\t\t\trequire.NoError(t, json.NewDecoder(r.Body).Decode(&query))\n\t\t\t\tif strings.Contains(query.Query, \"pushDir\") {\n\t\t\t\t\terr := json.Unmarshal(query.Variables, &query.PushDir)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tfmt.Fprint(w, `{\"data\":{\"pushDir\":{\"url\":\"https://some-org.atlasgo.cloud/dirs/314159/tags/12345\"}}}`)\n\t\t\t\t}\n\t\t\t\tif strings.Contains(query.Query, \"diffSyncDir\") {\n\t\t\t\t\terr := json.Unmarshal(query.Variables, &query.DiffSyncDir)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tfmt.Fprint(w, `{\"data\":{\"diffSyncDir\":{\"url\":\"https://some-org.atlasgo.cloud/dirs/314159/tags/12345\"}}}`)\n\t\t\t\t}\n\t\t\t\ttt.payloads = append(tt.payloads, query)\n\t\t\t}\n\t\t}\n\t\ttt.srv = httptest.NewServer(handler())\n\t\tt.Cleanup(tt.srv.Close)\n\t\treturn tt, generateHCL(t, token, tt.srv)\n\t}\n\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\trequire.NoError(t, err)\n\tinputContext := &atlasexec.RunContext{\n\t\tRepo:     \"testing-repo\",\n\t\tPath:     \"path/to/dir\",\n\t\tBranch:   \"testing-branch\",\n\t\tCommit:   \"sha123\",\n\t\tURL:      \"this://is/a/url\",\n\t\tUserID:   \"test-user-id\",\n\t\tUsername: \"test-user\",\n\t\tSCMType:  atlasexec.SCMTypeGithub,\n\t}\n\tt.Run(\"sync\", func(t *testing.T) {\n\t\tparams := &atlasexec.MigratePushParams{\n\t\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\t\tDirURL: \"file://testdata/migrations\",\n\t\t\tName:   \"test-dir-slug\",\n\t\t\tEnv:    \"test\",\n\t\t}\n\t\tt.Run(\"with context\", func(t *testing.T) {\n\t\t\ttt, atlasConfigURL := newHTTPTest()\n\t\t\tparams.ConfigURL = atlasConfigURL\n\t\t\tgot, err := c.MigratePush(context.Background(), params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, tt.payloads, 3)\n\t\t\trequire.Equal(t, `https://some-org.atlasgo.cloud/dirs/314159/tags/12345`, got)\n\t\t\tp := &tt.payloads[2]\n\t\t\trequire.Contains(t, p.Query, \"diffSyncDir\")\n\t\t\trequire.Equal(t, \"test-dir-slug\", p.DiffSyncDir.Input.Slug)\n\t\t\trequire.Equal(t, \"SQLITE\", p.DiffSyncDir.Input.Driver)\n\t\t\trequire.NotEmpty(t, p.DiffSyncDir.Input.Dir)\n\t\t})\n\t\tt.Run(\"without context\", func(t *testing.T) {\n\t\t\ttt, atlasConfigURL := newHTTPTest()\n\t\t\tparams.ConfigURL = atlasConfigURL\n\t\t\tparams.Context = inputContext\n\t\t\tgot, err := c.MigratePush(context.Background(), params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, `https://some-org.atlasgo.cloud/dirs/314159/tags/12345`, got)\n\t\t\trequire.Len(t, tt.payloads, 3)\n\t\t\tp := &tt.payloads[2]\n\t\t\trequire.Contains(t, p.Query, \"diffSyncDir\")\n\t\t\terr = json.Unmarshal(p.Variables, &p.DiffSyncDir)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, inputContext, p.DiffSyncDir.Input.Context)\n\t\t})\n\n\t})\n\tt.Run(\"push\", func(t *testing.T) {\n\t\ttt, atlasConfigURL := newHTTPTest()\n\t\tparams := &atlasexec.MigratePushParams{\n\t\t\tConfigURL: atlasConfigURL,\n\t\t\tDevURL:    \"sqlite://file?mode=memory\",\n\t\t\tDirURL:    \"file://testdata/migrations\",\n\t\t\tName:      \"test-dir-slug\",\n\t\t\tContext:   inputContext,\n\t\t\tEnv:       \"test\",\n\t\t\tTag:       \"this-is-my-tag\",\n\t\t}\n\t\tgot, err := c.MigratePush(context.Background(), params)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, `https://some-org.atlasgo.cloud/dirs/314159/tags/12345`, got)\n\t\trequire.Len(t, tt.payloads, 2)\n\t\tp := &tt.payloads[1]\n\t\trequire.Contains(t, p.Query, \"pushDir\")\n\t\trequire.Equal(t, \"test-dir-slug\", p.PushDir.Input.Slug)\n\t\trequire.Equal(t, \"SQLITE\", p.PushDir.Input.Driver)\n\t\trequire.Equal(t, \"this-is-my-tag\", p.PushDir.Input.Tag)\n\t\trequire.NotEmpty(t, p.PushDir.Input.Dir)\n\t})\n}\n\nfunc TestMigrateHash(t *testing.T) {\n\ttd := t.TempDir()\n\trequire.NoError(t, os.Mkdir(fmt.Sprintf(\"%s/migrations\", td), 0777))\n\trequire.NoError(t, os.WriteFile(fmt.Sprintf(\"%s/migrations/1.sql\", td), []byte(`create table t (c int not null)`), 0666))\n\tc, err := atlasexec.NewClient(td, \"atlas\")\n\trequire.NoError(t, err)\n\tinspect := func() error {\n\t\t_, err = c.SchemaInspect(context.Background(), &atlasexec.SchemaInspectParams{\n\t\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\t\tURL:    fmt.Sprintf(\"file://%s/migrations\", td),\n\t\t})\n\t\treturn err\n\t}\n\trequire.ErrorContains(t, inspect(), \"checksum file not found\")\n\trequire.NoError(t, c.MigrateHash(context.Background(), &atlasexec.MigrateHashParams{}))\n\trequire.FileExists(t, fmt.Sprintf(\"%s/migrations/atlas.sum\", td))\n\trequire.NoError(t, inspect())\n}\n\nfunc TestMigrateRebase(t *testing.T) {\n\ttd := t.TempDir()\n\trequire.NoError(t, os.Mkdir(fmt.Sprintf(\"%s/migrations\", td), 0777))\n\t// create initial migrations dir state\n\trequire.NoError(t, os.WriteFile(fmt.Sprintf(\"%s/migrations/2024030709.sql\", td), []byte(`create table t (c int not null)`), 0666))\n\trequire.NoError(t, os.WriteFile(fmt.Sprintf(\"%s/migrations/2024030711.sql\", td), []byte(\"alter table `t` add column `c3` text not null;\"), 0666))\n\tc, err := atlasexec.NewClient(td, \"atlas\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, c.MigrateHash(context.Background(), &atlasexec.MigrateHashParams{}))\n\trequire.FileExists(t, fmt.Sprintf(\"%s/migrations/atlas.sum\", td))\n\t// Print atlas.sum before adding a new migration\n\tbefore, err := os.ReadFile(fmt.Sprintf(\"%s/migrations/atlas.sum\", td))\n\trequire.NoError(t, err)\n\n\t// add a new migration\n\trequire.NoError(t, os.WriteFile(fmt.Sprintf(\"%s/migrations/2024030710.sql\", td), []byte(\"alter table `t` add column `c2` text not null;\"), 0666))\n\trequire.NoError(t, c.MigrateHash(context.Background(), &atlasexec.MigrateHashParams{}))\n\trequire.FileExists(t, fmt.Sprintf(\"%s/migrations/atlas.sum\", td))\n\trequire.NoError(t, c.MigrateRebase(context.Background(), &atlasexec.MigrateRebaseParams{\n\t\tFiles: []string{\n\t\t\t\"2024030711.sql\",\n\t\t},\n\t\tDirURL: fmt.Sprintf(\"file://%s/migrations\", td),\n\t}))\n\tinspect := func() error {\n\t\t_, err = c.SchemaInspect(context.Background(), &atlasexec.SchemaInspectParams{\n\t\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\t\tURL:    fmt.Sprintf(\"file://%s/migrations\", td),\n\t\t})\n\t\treturn err\n\t}\n\t// ensure sum file changes after rebase\n\tafter, err := os.ReadFile(fmt.Sprintf(\"%s/migrations/atlas.sum\", td))\n\trequire.NotEqual(t, before, after)\n\trequire.NoError(t, inspect())\n}\n\nfunc TestAtlasMigrate_Lint(t *testing.T) {\n\tt.Run(\"with broken config\", func(t *testing.T) {\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tgot, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{\n\t\t\tConfigURL: \"file://config-broken.hcl\",\n\t\t})\n\t\trequire.ErrorContains(t, err, `file \"config-broken.hcl\" was not found`)\n\t\trequire.Nil(t, got)\n\t})\n\tt.Run(\"with broken dev-url\", func(t *testing.T) {\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tgot, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{\n\t\t\tDirURL: \"file://atlasexec/testdata/migrations\",\n\t\t})\n\t\trequire.ErrorContains(t, err, `required flag(s) \"dev-url\" not set`)\n\t\trequire.Nil(t, got)\n\t})\n\tt.Run(\"broken dir\", func(t *testing.T) {\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tgot, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{\n\t\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\t\tDirURL: \"file://atlasexec/testdata/doesnotexist\",\n\t\t})\n\t\trequire.ErrorContains(t, err, `stat atlasexec/testdata/doesnotexist: no such file or directory`)\n\t\trequire.Nil(t, got)\n\t})\n\tt.Run(\"lint error parsing\", func(t *testing.T) {\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tgot, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{\n\t\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\t\tDirURL: \"file://testdata/migrations\",\n\t\t\tLatest: 1,\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.GreaterOrEqual(t, 4, len(got.Steps))\n\t\trequire.Equal(t, \"sqlite\", got.Env.Driver)\n\t\trequire.Equal(t, \"testdata/migrations\", got.Env.Dir)\n\t\trequire.Equal(t, \"sqlite://file?mode=memory\", got.Env.URL.String())\n\t\trequire.Equal(t, 1, len(got.Files))\n\t\texpectedReport := &atlasexec.FileReport{\n\t\t\tName: \"20230926085734_destructive-change.sql\",\n\t\t\tText: \"DROP TABLE t2;\\n\",\n\t\t\tReports: []sqlcheck.Report{{\n\t\t\t\tText: \"destructive changes detected\",\n\t\t\t\tDiagnostics: []sqlcheck.Diagnostic{{\n\t\t\t\t\tPos:  0,\n\t\t\t\t\tText: `Dropping table \"t2\"`,\n\t\t\t\t\tCode: \"DS102\",\n\t\t\t\t\tSuggestedFixes: []sqlcheck.SuggestedFix{{\n\t\t\t\t\t\tMessage: \"Add a pre-migration check to ensure table \\\"t2\\\" is empty before dropping it\",\n\t\t\t\t\t\tTextEdit: &sqlcheck.TextEdit{\n\t\t\t\t\t\t\tLine:    1,\n\t\t\t\t\t\t\tEnd:     1,\n\t\t\t\t\t\t\tNewText: \"-- 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;\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}},\n\t\t\t\t}},\n\t\t\t}},\n\t\t\tError: \"destructive changes detected\",\n\t\t}\n\t\trequire.EqualValues(t, expectedReport, got.Files[0])\n\t})\n\tt.Run(\"lint with manually parsing output\", func(t *testing.T) {\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tvar buf bytes.Buffer\n\t\terr = c.MigrateLintError(context.Background(), &atlasexec.MigrateLintParams{\n\t\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\t\tDirURL: \"file://testdata/migrations\",\n\t\t\tLatest: 1,\n\t\t\tWriter: &buf,\n\t\t})\n\t\trequire.Equal(t, atlasexec.ErrLint, err)\n\t\tvar raw json.RawMessage\n\t\trequire.NoError(t, json.NewDecoder(&buf).Decode(&raw))\n\t\trequire.Contains(t, string(raw), \"destructive changes detected\")\n\t})\n\tt.Run(\"lint uses --base and --latest\", func(t *testing.T) {\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tsummary, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{\n\t\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\t\tDirURL: \"file://testdata/migrations\",\n\t\t\tLatest: 1,\n\t\t\tBase:   \"atlas://test-dir\",\n\t\t})\n\t\trequire.ErrorContains(t, err, \"--latest, --git-base, and --base are mutually exclusive\")\n\t\trequire.Nil(t, summary)\n\t})\n}\n\nfunc TestAtlasMigrate_LintWithLogin(t *testing.T) {\n\ttype (\n\t\tmigrateLintReport struct {\n\t\t\tContext *atlasexec.RunContext `json:\"context\"`\n\t\t}\n\t\tgraphQLQuery struct {\n\t\t\tQuery             string          `json:\"query\"`\n\t\t\tVariables         json.RawMessage `json:\"variables\"`\n\t\t\tMigrateLintReport struct {\n\t\t\t\tmigrateLintReport `json:\"input\"`\n\t\t\t}\n\t\t}\n\t\tDir struct {\n\t\t\tName    string `json:\"name\"`\n\t\t\tContent string `json:\"content\"`\n\t\t\tSlug    string `json:\"slug\"`\n\t\t}\n\t\tdirsQueryResponse struct {\n\t\t\tData struct {\n\t\t\t\tDirs []Dir `json:\"dirs\"`\n\t\t\t} `json:\"data\"`\n\t\t}\n\t)\n\ttoken := \"123456789\"\n\thandler := func(payloads *[]graphQLQuery) http.HandlerFunc {\n\t\treturn func(w http.ResponseWriter, r *http.Request) {\n\t\t\trequire.Equal(t, \"Bearer \"+token, r.Header.Get(\"Authorization\"))\n\t\t\tvar query graphQLQuery\n\t\t\trequire.NoError(t, json.NewDecoder(r.Body).Decode(&query))\n\t\t\t*payloads = append(*payloads, query)\n\t\t\tswitch {\n\t\t\tcase strings.Contains(query.Query, \"mutation reportMigrationLint\"):\n\t\t\t\t_, err := fmt.Fprintf(w, `{ \"data\": { \"reportMigrationLint\": { \"url\": \"https://migration-lint-report-url\" } } }`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\tcase strings.Contains(query.Query, \"query dirs\"):\n\t\t\t\tdir, err := migrate.NewLocalDir(\"./testdata/migrations\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tad, err := migrate.ArchiveDir(dir)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tvar resp dirsQueryResponse\n\t\t\t\tresp.Data.Dirs = []Dir{{\n\t\t\t\t\tName:    \"test-dir-name\",\n\t\t\t\t\tSlug:    \"test-dir-slug\",\n\t\t\t\t\tContent: base64.StdEncoding.EncodeToString(ad),\n\t\t\t\t}}\n\t\t\t\tst2bytes, err := json.Marshal(resp)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\t_, err = fmt.Fprint(w, string(st2bytes))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t}\n\t}\n\tt.Run(\"Web and Writer params produces an error\", func(t *testing.T) {\n\t\tvar payloads []graphQLQuery\n\t\tsrv := httptest.NewServer(handler(&payloads))\n\t\tt.Cleanup(srv.Close)\n\t\tatlasConfigURL := generateHCL(t, token, srv)\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tparams := &atlasexec.MigrateLintParams{\n\t\t\tConfigURL: atlasConfigURL,\n\t\t\tDevURL:    \"sqlite://file?mode=memory\",\n\t\t\tDirURL:    \"file://testdata/migrations\",\n\t\t\tLatest:    1,\n\t\t\tWeb:       true,\n\t\t}\n\t\tgot, err := c.MigrateLint(context.Background(), params)\n\t\trequire.ErrorContains(t, err, \"Writer or Web reporting are not supported\")\n\t\trequire.Nil(t, got)\n\t\tparams.Web = false\n\t\tparams.Writer = &bytes.Buffer{}\n\t\tgot, err = c.MigrateLint(context.Background(), params)\n\t\trequire.ErrorContains(t, err, \"Writer or Web reporting are not supported\")\n\t\trequire.Nil(t, got)\n\t})\n\tt.Run(\"lint parse web output - no error - custom format\", func(t *testing.T) {\n\t\tvar payloads []graphQLQuery\n\t\tsrv := httptest.NewServer(handler(&payloads))\n\t\tt.Cleanup(srv.Close)\n\t\tatlasConfigURL := generateHCL(t, token, srv)\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tvar buf bytes.Buffer\n\t\terr = c.MigrateLintError(context.Background(), &atlasexec.MigrateLintParams{\n\t\t\tDevURL:    \"sqlite://file?mode=memory\",\n\t\t\tDirURL:    \"file://testdata/migrations\",\n\t\t\tConfigURL: atlasConfigURL,\n\t\t\tLatest:    1,\n\t\t\tWriter:    &buf,\n\t\t\tFormat:    \"{{ .URL }}\",\n\t\t\tWeb:       true,\n\t\t})\n\t\trequire.Equal(t, err, atlasexec.ErrLint)\n\t\trequire.Equal(t, strings.TrimSpace(buf.String()), \"https://migration-lint-report-url\")\n\t})\n\tt.Run(\"lint parse web output - no error - default format\", func(t *testing.T) {\n\t\tvar payloads []graphQLQuery\n\t\tsrv := httptest.NewServer(handler(&payloads))\n\t\tt.Cleanup(srv.Close)\n\t\tatlasConfigURL := generateHCL(t, token, srv)\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tvar buf bytes.Buffer\n\t\terr = c.MigrateLintError(context.Background(), &atlasexec.MigrateLintParams{\n\t\t\tDevURL:    \"sqlite://file?mode=memory\",\n\t\t\tDirURL:    \"file://testdata/migrations\",\n\t\t\tConfigURL: atlasConfigURL,\n\t\t\tLatest:    1,\n\t\t\tWriter:    &buf,\n\t\t\tWeb:       true,\n\t\t})\n\t\trequire.Equal(t, atlasexec.ErrLint, err)\n\t\tvar sr atlasexec.SummaryReport\n\t\trequire.NoError(t, json.NewDecoder(&buf).Decode(&sr))\n\t\trequire.Equal(t, \"https://migration-lint-report-url\", sr.URL)\n\t})\n\tt.Run(\"lint uses --base\", func(t *testing.T) {\n\t\tvar payloads []graphQLQuery\n\t\tsrv := httptest.NewServer(handler(&payloads))\n\t\tt.Cleanup(srv.Close)\n\t\tatlasConfigURL := generateHCL(t, token, srv)\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tsummary, err := c.MigrateLint(context.Background(), &atlasexec.MigrateLintParams{\n\t\t\tDevURL:    \"sqlite://file?mode=memory\",\n\t\t\tDirURL:    \"file://testdata/migrations\",\n\t\t\tConfigURL: atlasConfigURL,\n\t\t\tBase:      \"atlas://test-dir-slug\",\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.NotNil(t, summary)\n\t})\n\tt.Run(\"lint uses --context has error\", func(t *testing.T) {\n\t\tvar payloads []graphQLQuery\n\t\tsrv := httptest.NewServer(handler(&payloads))\n\t\tt.Cleanup(srv.Close)\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\tvar (\n\t\t\tbuf            bytes.Buffer\n\t\t\tatlasConfigURL = generateHCL(t, token, srv)\n\t\t\trunContext     = &atlasexec.RunContext{\n\t\t\t\tRepo:     \"testing-repo\",\n\t\t\t\tPath:     \"path/to/dir\",\n\t\t\t\tBranch:   \"testing-branch\",\n\t\t\t\tCommit:   \"sha123\",\n\t\t\t\tURL:      \"this://is/a/url\",\n\t\t\t\tUsername: \"test-user\",\n\t\t\t\tUserID:   \"test-user-id\",\n\t\t\t\tSCMType:  atlasexec.SCMTypeGithub,\n\t\t\t}\n\t\t)\n\t\terr = c.MigrateLintError(context.Background(), &atlasexec.MigrateLintParams{\n\t\t\tDevURL:    \"sqlite://file?mode=memory\",\n\t\t\tDirURL:    \"file://testdata/migrations\",\n\t\t\tConfigURL: atlasConfigURL,\n\t\t\tBase:      \"atlas://test-dir-slug\",\n\t\t\tContext:   runContext,\n\t\t\tWriter:    &buf,\n\t\t\tWeb:       true,\n\t\t})\n\t\trequire.Equal(t, atlasexec.ErrLint, err)\n\t\tvar sr atlasexec.SummaryReport\n\t\trequire.NoError(t, json.NewDecoder(&buf).Decode(&sr))\n\t\trequire.Equal(t, \"https://migration-lint-report-url\", sr.URL)\n\t\tfound := false\n\t\tfor _, query := range payloads {\n\t\t\tif !strings.Contains(query.Query, \"mutation reportMigrationLint\") {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfound = true\n\t\t\trequire.NoError(t, json.Unmarshal(query.Variables, &query.MigrateLintReport))\n\t\t\trequire.Equal(t, runContext, query.MigrateLintReport.Context)\n\t\t}\n\t\trequire.True(t, found)\n\t})\n}\n\nfunc TestMigrate_Diff(t *testing.T) {\n\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\trequire.NoError(t, err)\n\ttd := t.TempDir()\n\trequire.NoError(t, os.WriteFile(fmt.Sprintf(\"%s/schema.sql\", td), []byte(`create table t (c int not null)`), 0666))\n\tparams := &atlasexec.MigrateDiffParams{\n\t\tToURL:  fmt.Sprintf(\"file://%s/schema.sql\", td),\n\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\tDirURL: \"file://testdata/migrations\",\n\t\tName:   \"test-diff\",\n\t}\n\toutput, err := c.MigrateDiff(context.Background(), params)\n\trequire.NoError(t, err)\n\trequire.Len(t, output.Files, 1)\n\trequire.Contains(t, output.Files[0].Name, \"test-diff.sql\")\n\trequire.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\")\n\trequire.Equal(t, output.Dir, \"file://testdata/migrations?format=atlas\")\n\n\t// No diff\n\tparams = &atlasexec.MigrateDiffParams{\n\t\tToURL:  \"file://testdata/migrations\",\n\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\tDirURL: \"file://testdata/migrations\",\n\t\tName:   \"test-diff\",\n\t}\n\toutput, err = c.MigrateDiff(context.Background(), params)\n\trequire.NoError(t, err)\n\trequire.Len(t, output.Files, 0)\n}\n"
  },
  {
    "path": "atlasexec/atlas_models.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n)\n\ntype (\n\t// File wraps migrate.File to implement json.Marshaler.\n\tFile struct {\n\t\tName        string `json:\"Name,omitempty\"`\n\t\tVersion     string `json:\"Version,omitempty\"`\n\t\tDescription string `json:\"Description,omitempty\"`\n\t\tContent     string `json:\"Content,omitempty\"`\n\t}\n\t// AppliedFile is part of a MigrateApply containing information about an applied file in a migration attempt.\n\tAppliedFile struct {\n\t\tFile\n\t\tStart   time.Time\n\t\tEnd     time.Time\n\t\tSkipped int           // Amount of skipped SQL statements in a partially applied file.\n\t\tApplied []string      // SQL statements applied with success\n\t\tChecks  []*FileChecks // Assertion checks\n\t\tError   *struct {\n\t\t\tStmt string // SQL statement that failed.\n\t\t\tText string // Error returned by the database.\n\t\t}\n\t}\n\t// RevertedFile is part of a MigrateDown containing information about a reverted file in a downgrade attempt.\n\tRevertedFile struct {\n\t\tFile\n\t\tStart   time.Time\n\t\tEnd     time.Time\n\t\tSkipped int      // Amount of skipped SQL statements in a partially applied file.\n\t\tApplied []string // SQL statements applied with success\n\t\tScope   string   // Scope of the revert. e.g., statement, versions, etc.\n\t\tError   *struct {\n\t\t\tStmt string // SQL statement that failed.\n\t\t\tText string // Error returned by the database.\n\t\t}\n\t}\n\t// A SummaryReport contains a summary of the analysis of all files.\n\t// It is used as an input to templates to report the CI results.\n\tSummaryReport struct {\n\t\tURL string `json:\"URL,omitempty\"` // URL of the report, if exists.\n\t\t// Env holds the environment information.\n\t\tEnv struct {\n\t\t\tDriver string         `json:\"Driver,omitempty\"` // Driver name.\n\t\t\tURL    *sqlclient.URL `json:\"URL,omitempty\"`    // URL to dev database.\n\t\t\tDir    string         `json:\"Dir,omitempty\"`    // Path to migration directory.\n\t\t}\n\t\t// Schema versions found by the runner.\n\t\tSchema struct {\n\t\t\tCurrent string `json:\"Current,omitempty\"` // Current schema.\n\t\t\tDesired string `json:\"Desired,omitempty\"` // Desired schema.\n\t\t}\n\t\t// Steps of the analysis. Added in verbose mode.\n\t\tSteps []*StepReport `json:\"Steps,omitempty\"`\n\t\t// Files reports. Non-empty in case there are findings.\n\t\tFiles []*FileReport `json:\"Files,omitempty\"`\n\t}\n\t// StepReport contains a summary of the analysis of a single step.\n\tStepReport struct {\n\t\tName   string      `json:\"Name,omitempty\"`   // Step name.\n\t\tText   string      `json:\"Text,omitempty\"`   // Step description.\n\t\tError  string      `json:\"Error,omitempty\"`  // Error that cause the execution to halt.\n\t\tResult *FileReport `json:\"Result,omitempty\"` // Result of the step. For example, a diagnostic.\n\t}\n\t// FileReport contains a summary of the analysis of a single file.\n\tFileReport struct {\n\t\tName    string            `json:\"Name,omitempty\"`    // Name of the file.\n\t\tText    string            `json:\"Text,omitempty\"`    // Contents of the file.\n\t\tReports []sqlcheck.Report `json:\"Reports,omitempty\"` // List of reports.\n\t\tError   string            `json:\"Error,omitempty\"`   // File specific error.\n\t}\n\t// FileChecks represents a set of checks to run before applying a file.\n\tFileChecks struct {\n\t\tName  string     `json:\"Name,omitempty\"`  // File/group name.\n\t\tStmts []*Check   `json:\"Stmts,omitempty\"` // Checks statements executed.\n\t\tError *StmtError `json:\"Error,omitempty\"` // Assertion error.\n\t\tStart time.Time  `json:\"Start,omitempty\"` // Start assertion time.\n\t\tEnd   time.Time  `json:\"End,omitempty\"`   // End assertion time.\n\t}\n\t// Check represents an assertion and its status.\n\tCheck struct {\n\t\tStmt  string  `json:\"Stmt,omitempty\"`  // Assertion statement.\n\t\tError *string `json:\"Error,omitempty\"` // Assertion error, if any.\n\t}\n\t// StmtError groups a statement with its execution error.\n\tStmtError struct {\n\t\tStmt string `json:\"Stmt,omitempty\"` // SQL statement that failed.\n\t\tText string `json:\"Text,omitempty\"` // Error message as returned by the database.\n\t}\n\t// Env holds the environment information.\n\tEnv struct {\n\t\tDriver string         `json:\"Driver,omitempty\"` // Driver name.\n\t\tURL    *sqlclient.URL `json:\"URL,omitempty\"`    // URL to dev database.\n\t\tDir    string         `json:\"Dir,omitempty\"`    // Path to migration directory.\n\t}\n\t// Changes represents a list of changes that are pending or applied.\n\tChanges struct {\n\t\tApplied []string   `json:\"Applied,omitempty\"` // SQL changes applied with success\n\t\tPending []string   `json:\"Pending,omitempty\"` // SQL changes that were not applied\n\t\tError   *StmtError `json:\"Error,omitempty\"`   // Error that occurred during applying\n\t}\n\t// A Revision denotes an applied migration in a deployment. Used to track migration executions state of a database.\n\tRevision struct {\n\t\tVersion         string        `json:\"Version\"`             // Version of the migration.\n\t\tDescription     string        `json:\"Description\"`         // Description of this migration.\n\t\tType            string        `json:\"Type\"`                // Type of the migration.\n\t\tApplied         int           `json:\"Applied\"`             // Applied amount of statements in the migration.\n\t\tTotal           int           `json:\"Total\"`               // Total amount of statements in the migration.\n\t\tExecutedAt      time.Time     `json:\"ExecutedAt\"`          // ExecutedAt is the starting point of execution.\n\t\tExecutionTime   time.Duration `json:\"ExecutionTime\"`       // ExecutionTime of the migration.\n\t\tError           string        `json:\"Error,omitempty\"`     // Error of the migration, if any occurred.\n\t\tErrorStmt       string        `json:\"ErrorStmt,omitempty\"` // ErrorStmt is the statement that raised Error.\n\t\tOperatorVersion string        `json:\"OperatorVersion\"`     // OperatorVersion that executed this migration.\n\t}\n\t// A Report describes a schema analysis report with an optional specific diagnostic.\n\tReport struct {\n\t\tText        string       `json:\"Text\"`                  // Report text.\n\t\tDesc        string       `json:\"Desc,omitempty\"`        // Optional description (secondary text).\n\t\tError       bool         `json:\"Error,omitempty\"`       // Report is an error report.\n\t\tDiagnostics []Diagnostic `json:\"Diagnostics,omitempty\"` // Report diagnostics.\n\t}\n\t// A Diagnostic is a text associated with a specific position of a definition/element in a file.\n\tDiagnostic struct {\n\t\tPos  *schema.Pos `json:\"Pos,omitempty\"`  // Element position.\n\t\tText string      `json:\"Text\"`           // Diagnostic text.\n\t\tCode string      `json:\"Code,omitempty\"` // Code describes the check (optional).\n\t}\n\t// TableSizeMetric represents a table size metric from schema stats\n\tTableSizeMetric struct {\n\t\tSchema string  `json:\"schema\"`\n\t\tTable  string  `json:\"table\"`\n\t\tValue  float64 `json:\"value\"`\n\t}\n)\n\n// MetricTableSizeBytes is the name of the table size metric in bytes.\nconst MetricTableSizeBytes = \"atlas_table_size_bytes\"\n\n// DiagnosticsCount returns the total number of diagnostics in the report.\nfunc (r *SummaryReport) DiagnosticsCount() int {\n\tvar n int\n\tfor _, f := range r.Files {\n\t\tfor _, r := range f.Reports {\n\t\t\tn += len(r.Diagnostics)\n\t\t}\n\t}\n\treturn n\n}\n\n// Errors returns the errors in the summary report, if exists.\nfunc (r *SummaryReport) Errors() []error {\n\tvar errs []error\n\tfor _, f := range r.Files {\n\t\tif f.Error != \"\" {\n\t\t\terrs = append(errs, errors.New(f.Error))\n\t\t}\n\t}\n\treturn errs\n}\n"
  },
  {
    "path": "atlasexec/atlas_schema.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n)\n\ntype (\n\t// SchemaPushParams are the parameters for the `schema push` command.\n\tSchemaPushParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *RunContext\n\t\tDevURL    string\n\n\t\tURL         []string // Desired schema URL(s) to push\n\t\tSchema      []string // If set, only the specified schemas are pushed.\n\t\tName        string   // Name of the schema (repo) to push to.\n\t\tTag         string   // Tag to push the schema with\n\t\tVersion     string   // Version of the schema to push. Defaults to the current timestamp.\n\t\tDescription string   // Description of the schema changes.\n\t}\n\t// SchemaPush represents the result of a 'schema push' command.\n\tSchemaPush struct {\n\t\tLink string\n\t\tSlug string\n\t\tURL  string\n\t}\n\t// SchemaApplyParams are the parameters for the `schema apply` command.\n\tSchemaApplyParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tDevURL    string\n\n\t\tURL         string\n\t\tTo          string // TODO: change to []string\n\t\tTxMode      string\n\t\tExclude     []string\n\t\tInclude     []string\n\t\tSchema      []string\n\t\tDryRun      bool   // If true, --dry-run is set.\n\t\tAutoApprove bool   // If true, --auto-approve is set.\n\t\tPlanURL     string // URL of the plan in Atlas format (atlas://<repo>/plans/<id>). (optional)\n\t\tLockName    string\n\t}\n\t// SchemaApply represents the result of a 'schema apply' command.\n\tSchemaApply struct {\n\t\tEnv\n\t\t// Changes holds the changes applied to the database.\n\t\t// Exists for backward compatibility with the old schema\n\t\t// apply structure as old SDK versions rely on it.\n\t\tChanges Changes      `json:\"Changes,omitempty\"`\n\t\tError   string       `json:\"Error,omitempty\"`   // Any error that occurred during execution.\n\t\tStart   time.Time    `json:\"Start,omitempty\"`   // When apply (including plan) started.\n\t\tEnd     time.Time    `json:\"End,omitempty\"`     // When apply ended.\n\t\tApplied *AppliedFile `json:\"Applied,omitempty\"` // Applied migration file (pre-planned or computed).\n\t\t// Plan information might be partially filled. For example, if lint is done\n\t\t// during plan-stage, the linting report is available in the Plan field. If\n\t\t// the migration is pre-planned migration, the File.URL is set, etc.\n\t\tPlan *SchemaPlan `json:\"Plan,omitempty\"`\n\t}\n\t// SchemaApplyError is returned when an error occurred\n\t// during a schema applying attempt.\n\tSchemaApplyError struct {\n\t\tResult []*SchemaApply\n\t\tStderr string\n\t}\n\t// SchemaInspectParams are the parameters for the `schema inspect` command.\n\tSchemaInspectParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tFormat    string\n\t\tDevURL    string\n\n\t\tURL     string\n\t\tExclude []string\n\t\tInclude []string\n\t\tSchema  []string\n\t}\n\t// SchemaTestParams are the parameters for the `schema test` command.\n\tSchemaTestParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tDevURL    string\n\n\t\tURL   string\n\t\tRun   string\n\t\tPaths []string\n\t}\n\t// SchemaPlanParams are the parameters for the `schema plan` command.\n\tSchemaPlanParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *RunContext\n\t\tDevURL    string\n\t\tExclude   []string\n\t\tInclude   []string\n\t\tSchema    []string\n\n\t\tFrom, To   []string\n\t\tRepo       string\n\t\tName       string\n\t\tDirectives []string\n\t\t// The below are mutually exclusive and can be replaced\n\t\t// with the 'schema plan' sub-commands instead.\n\t\tDryRun     bool // If false, --auto-approve is set.\n\t\tPending    bool\n\t\tPush, Save bool\n\t}\n\t// SchemaPlanListParams are the parameters for the `schema plan list` command.\n\tSchemaPlanListParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *RunContext\n\t\tDevURL    string\n\t\tSchema    []string\n\t\tExclude   []string\n\t\tInclude   []string\n\n\t\tFrom, To []string\n\t\tRepo     string\n\t\tPending  bool // If true, only pending plans are listed.\n\t}\n\t// SchemaPlanPushParams are the parameters for the `schema plan push` command.\n\tSchemaPlanPushParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *RunContext\n\t\tDevURL    string\n\t\tSchema    []string\n\t\tExclude   []string\n\t\tInclude   []string\n\n\t\tFrom, To []string\n\t\tRepo     string\n\t\tPending  bool   // Push plan in pending state.\n\t\tFile     string // File to push. (optional)\n\t}\n\t// SchemaPlanPullParams are the parameters for the `schema plan pull` command.\n\tSchemaPlanPullParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tURL       string // URL to the plan in Atlas format. (required)\n\t}\n\t// SchemaPlanLintParams are the parameters for the `schema plan lint` command.\n\tSchemaPlanLintParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *RunContext\n\t\tDevURL    string\n\t\tSchema    []string\n\t\tExclude   []string\n\t\tInclude   []string\n\n\t\tFrom, To []string\n\t\tRepo     string\n\t\tFile     string\n\t}\n\t// SchemaPlanValidateParams are the parameters for the `schema plan validate` command.\n\tSchemaPlanValidateParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\t\tContext   *RunContext\n\t\tDevURL    string\n\t\tSchema    []string\n\t\tExclude   []string\n\t\tInclude   []string\n\n\t\tFrom, To []string\n\t\tRepo     string\n\t\tName     string\n\t\tFile     string\n\t}\n\t// SchemaPlanApproveParams are the parameters for the `schema plan approve` command.\n\tSchemaPlanApproveParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\n\t\tURL string\n\t}\n\t// SchemaPlan is the result of a 'schema plan' command.\n\tSchemaPlan struct {\n\t\tEnv   Env             `json:\"Env,omitempty\"`   // Environment info.\n\t\tRepo  string          `json:\"Repo,omitempty\"`  // Repository name.\n\t\tLint  *SummaryReport  `json:\"Lint,omitempty\"`  // Lint report.\n\t\tFile  *SchemaPlanFile `json:\"File,omitempty\"`  // Plan file.\n\t\tError string          `json:\"Error,omitempty\"` // Any error occurred during planning.\n\t}\n\t// SchemaPlanApprove is the result of a 'schema plan approve' command.\n\tSchemaPlanApprove struct {\n\t\tURL    string `json:\"URL,omitempty\"`    // URL of the plan in Atlas format.\n\t\tLink   string `json:\"Link,omitempty\"`   // Link to the plan in the registry.\n\t\tStatus string `json:\"Status,omitempty\"` // Status of the plan in the registry.\n\t}\n\t// SchemaPlanFile is a JSON representation of a schema plan file.\n\tSchemaPlanFile struct {\n\t\tName      string          `json:\"Name,omitempty\"`      // Name of the plan.\n\t\tFromHash  string          `json:\"FromHash,omitempty\"`  // Hash of the 'from' realm.\n\t\tFromDesc  string          `json:\"FromDesc,omitempty\"`  // Optional description of the 'from' state.\n\t\tToHash    string          `json:\"ToHash,omitempty\"`    // Hash of the 'to' realm.\n\t\tToDesc    string          `json:\"ToDesc,omitempty\"`    // Optional description of the 'to' state.\n\t\tMigration string          `json:\"Migration,omitempty\"` // Migration SQL.\n\t\tStmts     []*migrate.Stmt `json:\"Stmts,omitempty\"`     // Statements in the migration (available only in the JSON output).\n\t\t// registry only fields.\n\t\tURL    string `json:\"URL,omitempty\"`    // URL of the plan in Atlas format.\n\t\tLink   string `json:\"Link,omitempty\"`   // Link to the plan in the registry.\n\t\tStatus string `json:\"Status,omitempty\"` // Status of the plan in the registry.\n\t}\n\t// SchemaCleanParams are the parameters for the `schema clean` command.\n\tSchemaCleanParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\n\t\tURL         string // URL of the schema to clean. (required)\n\t\tDryRun      bool   // If true, --dry-run is set.\n\t\tAutoApprove bool   // If true, --auto-approve is set.\n\t}\n\t// SchemaClean represents the result of a 'schema clean' command.\n\tSchemaClean struct {\n\t\tEnv\n\t\tStart   time.Time    `json:\"Start,omitempty\"`   // When clean started.\n\t\tEnd     time.Time    `json:\"End,omitempty\"`     // When clean ended.\n\t\tApplied *AppliedFile `json:\"Applied,omitempty\"` // Applied migration file.\n\t\tError   string       `json:\"Error,omitempty\"`   // Any error that occurred during execution.\n\t}\n\t// SchemaLintParams are the parameters for the `schema lint` command.\n\tSchemaLintParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\n\t\tURL    []string // Schema URL(s) to lint\n\t\tSchema []string // If set, only the specified schemas are linted.\n\t\tFormat string\n\t\tDevURL string\n\t}\n\t// SchemaLintReport holds the results of a schema lint operation\n\tSchemaLintReport struct {\n\t\tSteps []Report `json:\"Steps,omitempty\"`\n\t}\n\n\t// SchemaStatsInspectParams are the parameters for the `schema stat inspect` command.\n\tSchemaStatsInspectParams struct {\n\t\tConfigURL string\n\t\tEnv       string\n\t\tVars      VarArgs\n\n\t\tURL     string\n\t\tExclude []string\n\t\tInclude []string\n\t\tSchema  []string\n\t}\n)\n\n// SchemaPush runs the 'schema push' command.\nfunc (c *Client) SchemaPush(ctx context.Context, params *SchemaPushParams) (*SchemaPush, error) {\n\targs := []string{\"schema\", \"push\", \"--format\", \"{{ json . }}\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// Hidden flags\n\tif params.Context != nil {\n\t\tbuf, err := json.Marshal(params.Context)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\t// Flags of the 'schema push' sub-commands\n\targs = append(args, repeatFlag(\"--url\", params.URL)...)\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif len(params.Schema) > 0 {\n\t\targs = append(args, \"--schema\", listString(params.Schema))\n\t}\n\tif params.Tag != \"\" {\n\t\targs = append(args, \"--tag\", params.Tag)\n\t}\n\tif params.Version != \"\" {\n\t\targs = append(args, \"--version\", params.Version)\n\t}\n\tif params.Description != \"\" {\n\t\targs = append(args, \"--desc\", params.Description)\n\t}\n\tif params.Name != \"\" {\n\t\targs = append(args, params.Name)\n\t}\n\treturn firstResult(jsonDecode[SchemaPush](c.runCommand(ctx, args)))\n}\n\n// SchemaApply runs the 'schema apply' command.\nfunc (c *Client) SchemaApply(ctx context.Context, params *SchemaApplyParams) (*SchemaApply, error) {\n\treturn firstResult(c.SchemaApplySlice(ctx, params))\n}\n\n// SchemaApplySlice runs the 'schema apply' command for multiple targets.\nfunc (c *Client) SchemaApplySlice(ctx context.Context, params *SchemaApplyParams) ([]*SchemaApply, error) {\n\targs := []string{\"schema\", \"apply\", \"--format\", \"{{ json . }}\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// Flags of the 'schema apply' sub-commands\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t}\n\tif params.To != \"\" {\n\t\targs = append(args, \"--to\", params.To)\n\t}\n\tif params.TxMode != \"\" {\n\t\targs = append(args, \"--tx-mode\", params.TxMode)\n\t}\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif len(params.Schema) > 0 {\n\t\targs = append(args, \"--schema\", listString(params.Schema))\n\t}\n\tif len(params.Exclude) > 0 {\n\t\targs = append(args, \"--exclude\", listString(params.Exclude))\n\t}\n\tif len(params.Include) > 0 {\n\t\targs = append(args, \"--include\", listString(params.Include))\n\t}\n\tif params.PlanURL != \"\" {\n\t\targs = append(args, \"--plan\", params.PlanURL)\n\t}\n\tif params.LockName != \"\" {\n\t\targs = append(args, \"--lock-name\", params.LockName)\n\t}\n\tswitch {\n\tcase params.DryRun:\n\t\targs = append(args, \"--dry-run\")\n\tcase params.AutoApprove:\n\t\targs = append(args, \"--auto-approve\")\n\t}\n\treturn jsonDecodeErr(newSchemaApplyError)(c.runCommand(ctx, args))\n}\n\n// SchemaInspect runs the 'schema inspect' command.\nfunc (c *Client) SchemaInspect(ctx context.Context, params *SchemaInspectParams) (string, error) {\n\targs := []string{\"schema\", \"inspect\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t}\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tswitch {\n\tcase params.Format == \"sql\":\n\t\targs = append(args, \"--format\", \"{{ sql . }}\")\n\tcase params.Format != \"\":\n\t\targs = append(args, \"--format\", params.Format)\n\t}\n\tif len(params.Schema) > 0 {\n\t\targs = append(args, \"--schema\", listString(params.Schema))\n\t}\n\tif len(params.Exclude) > 0 {\n\t\targs = append(args, \"--exclude\", listString(params.Exclude))\n\t}\n\tif len(params.Include) > 0 {\n\t\targs = append(args, \"--include\", listString(params.Include))\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\treturn stringVal(c.runCommand(ctx, args))\n}\n\n// SchemaTest runs the 'schema test' command.\nfunc (c *Client) SchemaTest(ctx context.Context, params *SchemaTestParams) (string, error) {\n\targs := []string{\"schema\", \"test\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t}\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif params.Run != \"\" {\n\t\targs = append(args, \"--run\", params.Run)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\tif len(params.Paths) > 0 {\n\t\targs = append(args, params.Paths...)\n\t}\n\treturn stringVal(c.runCommand(ctx, args))\n}\n\n// SchemaPlan runs the `schema plan` command.\nfunc (c *Client) SchemaPlan(ctx context.Context, params *SchemaPlanParams) (*SchemaPlan, error) {\n\targs := []string{\"schema\", \"plan\", \"--format\", \"{{ json . }}\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// Hidden flags\n\tif params.Context != nil {\n\t\tbuf, err := json.Marshal(params.Context)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\t// Flags of the 'schema plan' sub-commands\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif len(params.Schema) > 0 {\n\t\targs = append(args, \"--schema\", listString(params.Schema))\n\t}\n\tif len(params.Exclude) > 0 {\n\t\targs = append(args, \"--exclude\", listString(params.Exclude))\n\t}\n\tif len(params.Include) > 0 {\n\t\targs = append(args, \"--include\", listString(params.Include))\n\t}\n\tif len(params.From) > 0 {\n\t\targs = append(args, \"--from\", listString(params.From))\n\t}\n\tif len(params.To) > 0 {\n\t\targs = append(args, \"--to\", listString(params.To))\n\t}\n\tif params.Name != \"\" {\n\t\targs = append(args, \"--name\", params.Name)\n\t}\n\tif params.Repo != \"\" {\n\t\targs = append(args, \"--repo\", params.Repo)\n\t}\n\tif params.Save {\n\t\targs = append(args, \"--save\")\n\t}\n\tif params.Push {\n\t\targs = append(args, \"--push\")\n\t}\n\tif params.Pending {\n\t\targs = append(args, \"--pending\")\n\t}\n\tif params.DryRun {\n\t\targs = append(args, \"--dry-run\")\n\t} else {\n\t\targs = append(args, \"--auto-approve\")\n\t}\n\tfor _, d := range params.Directives {\n\t\targs = append(args, \"--directive\", strconv.Quote(d))\n\t}\n\t// NOTE: This command only support one result.\n\treturn firstResult(jsonDecode[SchemaPlan](c.runCommand(ctx, args)))\n}\n\n// SchemaPlanList runs the `schema plan list` command.\nfunc (c *Client) SchemaPlanList(ctx context.Context, params *SchemaPlanListParams) ([]SchemaPlanFile, error) {\n\targs := []string{\"schema\", \"plan\", \"list\", \"--format\", \"{{ json . }}\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// Hidden flags\n\tif params.Context != nil {\n\t\tbuf, err := json.Marshal(params.Context)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\t// Flags of the 'schema plan lint' sub-commands\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif len(params.Schema) > 0 {\n\t\targs = append(args, \"--schema\", listString(params.Schema))\n\t}\n\tif len(params.Exclude) > 0 {\n\t\targs = append(args, \"--exclude\", listString(params.Exclude))\n\t}\n\tif len(params.Include) > 0 {\n\t\targs = append(args, \"--include\", listString(params.Include))\n\t}\n\tif len(params.From) > 0 {\n\t\targs = append(args, \"--from\", listString(params.From))\n\t}\n\tif len(params.To) > 0 {\n\t\targs = append(args, \"--to\", listString(params.To))\n\t}\n\tif params.Repo != \"\" {\n\t\targs = append(args, \"--repo\", params.Repo)\n\t}\n\tif params.Pending {\n\t\targs = append(args, \"--pending\")\n\t}\n\targs = append(args, \"--auto-approve\")\n\t// NOTE: This command only support one result.\n\tv, err := firstResult(jsonDecode[[]SchemaPlanFile](c.runCommand(ctx, args)))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn *v, nil\n}\n\n// SchemaPlanPush runs the `schema plan push` command.\nfunc (c *Client) SchemaPlanPush(ctx context.Context, params *SchemaPlanPushParams) (string, error) {\n\targs := []string{\"schema\", \"plan\", \"push\", \"--format\", \"{{ json . }}\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// Hidden flags\n\tif params.Context != nil {\n\t\tbuf, err := json.Marshal(params.Context)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\t// Flags of the 'schema plan push' sub-commands\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif len(params.Schema) > 0 {\n\t\targs = append(args, \"--schema\", listString(params.Schema))\n\t}\n\tif len(params.Exclude) > 0 {\n\t\targs = append(args, \"--exclude\", listString(params.Exclude))\n\t}\n\tif len(params.Include) > 0 {\n\t\targs = append(args, \"--include\", listString(params.Include))\n\t}\n\tif len(params.From) > 0 {\n\t\targs = append(args, \"--from\", listString(params.From))\n\t}\n\tif len(params.To) > 0 {\n\t\targs = append(args, \"--to\", listString(params.To))\n\t}\n\tif params.File != \"\" {\n\t\targs = append(args, \"--file\", params.File)\n\t} else {\n\t\treturn \"\", &InvalidParamsError{\"schema plan push\", \"missing required flag --file\"}\n\t}\n\tif params.Repo != \"\" {\n\t\targs = append(args, \"--repo\", params.Repo)\n\t}\n\tif params.Pending {\n\t\targs = append(args, \"--pending\")\n\t} else {\n\t\targs = append(args, \"--auto-approve\")\n\t}\n\treturn stringVal(c.runCommand(ctx, args))\n}\n\n// SchemaPlanPush runs the `schema plan pull` command.\nfunc (c *Client) SchemaPlanPull(ctx context.Context, params *SchemaPlanPullParams) (string, error) {\n\targs := []string{\"schema\", \"plan\", \"pull\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// Flags of the 'schema plan pull' sub-commands\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t} else {\n\t\treturn \"\", &InvalidParamsError{\"schema plan pull\", \"missing required flag --url\"}\n\t}\n\treturn stringVal(c.runCommand(ctx, args))\n}\n\n// SchemaPlanLint runs the `schema plan lint` command.\nfunc (c *Client) SchemaPlanLint(ctx context.Context, params *SchemaPlanLintParams) (*SchemaPlan, error) {\n\targs := []string{\"schema\", \"plan\", \"lint\", \"--format\", \"{{ json . }}\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// Hidden flags\n\tif params.Context != nil {\n\t\tbuf, err := json.Marshal(params.Context)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\t// Flags of the 'schema plan lint' sub-commands\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif len(params.Schema) > 0 {\n\t\targs = append(args, \"--schema\", listString(params.Schema))\n\t}\n\tif len(params.Exclude) > 0 {\n\t\targs = append(args, \"--exclude\", listString(params.Exclude))\n\t}\n\tif len(params.Include) > 0 {\n\t\targs = append(args, \"--include\", listString(params.Include))\n\t}\n\tif len(params.From) > 0 {\n\t\targs = append(args, \"--from\", listString(params.From))\n\t}\n\tif len(params.To) > 0 {\n\t\targs = append(args, \"--to\", listString(params.To))\n\t}\n\tif params.File != \"\" {\n\t\targs = append(args, \"--file\", params.File)\n\t} else {\n\t\treturn nil, &InvalidParamsError{\"schema plan lint\", \"missing required flag --file\"}\n\t}\n\tif params.Repo != \"\" {\n\t\targs = append(args, \"--repo\", params.Repo)\n\t}\n\targs = append(args, \"--auto-approve\")\n\t// NOTE: This command only support one result.\n\treturn firstResult(jsonDecode[SchemaPlan](c.runCommand(ctx, args)))\n}\n\n// SchemaPlanValidate runs the `schema plan validate` command.\nfunc (c *Client) SchemaPlanValidate(ctx context.Context, params *SchemaPlanValidateParams) error {\n\targs := []string{\"schema\", \"plan\", \"validate\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// Hidden flags\n\tif params.Context != nil {\n\t\tbuf, err := json.Marshal(params.Context)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\targs = append(args, \"--context\", string(buf))\n\t}\n\t// Flags of the 'schema plan validate' sub-commands\n\tif params.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", params.DevURL)\n\t}\n\tif len(params.Schema) > 0 {\n\t\targs = append(args, \"--schema\", listString(params.Schema))\n\t}\n\tif len(params.Exclude) > 0 {\n\t\targs = append(args, \"--exclude\", listString(params.Exclude))\n\t}\n\tif len(params.Include) > 0 {\n\t\targs = append(args, \"--include\", listString(params.Include))\n\t}\n\tif len(params.From) > 0 {\n\t\targs = append(args, \"--from\", listString(params.From))\n\t}\n\tif len(params.To) > 0 {\n\t\targs = append(args, \"--to\", listString(params.To))\n\t}\n\tif params.File != \"\" {\n\t\targs = append(args, \"--file\", params.File)\n\t} else {\n\t\treturn &InvalidParamsError{\"schema plan validate\", \"missing required flag --file\"}\n\t}\n\tif params.Name != \"\" {\n\t\targs = append(args, \"--name\", params.Name)\n\t}\n\tif params.Repo != \"\" {\n\t\targs = append(args, \"--repo\", params.Repo)\n\t}\n\targs = append(args, \"--auto-approve\")\n\t_, err := stringVal(c.runCommand(ctx, args))\n\treturn err\n}\n\n// SchemaPlanApprove runs the `schema plan approve` command.\nfunc (c *Client) SchemaPlanApprove(ctx context.Context, params *SchemaPlanApproveParams) (*SchemaPlanApprove, error) {\n\targs := []string{\"schema\", \"plan\", \"approve\", \"--format\", \"{{ json . }}\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// Flags of the 'schema plan approve' sub-commands\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t} else {\n\t\treturn nil, &InvalidParamsError{\"schema plan approve\", \"missing required flag --url\"}\n\t}\n\t// NOTE: This command only support one result.\n\treturn firstResult(jsonDecode[SchemaPlanApprove](c.runCommand(ctx, args)))\n}\n\n// SchemaClean runs the `schema clean` command.\nfunc (c *Client) SchemaClean(ctx context.Context, params *SchemaCleanParams) (*SchemaClean, error) {\n\targs := []string{\"schema\", \"clean\", \"--format\", \"{{ json . }}\"}\n\t// Global flags\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\t// Flags of the 'schema clean' sub-commands\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t}\n\tswitch {\n\tcase params.DryRun:\n\t\targs = append(args, \"--dry-run\")\n\tcase params.AutoApprove:\n\t\targs = append(args, \"--auto-approve\")\n\t}\n\treturn firstResult(jsonDecode[SchemaClean](c.runCommand(ctx, args)))\n}\n\n// SchemaLint runs the 'schema lint' command.\nfunc (c *Client) SchemaLint(ctx context.Context, params *SchemaLintParams) (*SchemaLintReport, error) {\n\targs, err := params.AsArgs()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn firstResult(jsonDecode[SchemaLintReport](c.runCommand(ctx, args)))\n}\n\n// SchemaStatsInspect runs the 'schema stats inspect' command.\nfunc (c *Client) SchemaStatsInspect(ctx context.Context, params *SchemaStatsInspectParams) (string, error) {\n\targs := []string{\"schema\", \"stats\", \"inspect\", \"--format\", \"{{ json .Realm }}\"}\n\tif params.Env != \"\" {\n\t\targs = append(args, \"--env\", params.Env)\n\t}\n\tif params.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", params.ConfigURL)\n\t}\n\tif params.URL != \"\" {\n\t\targs = append(args, \"--url\", params.URL)\n\t}\n\tif len(params.Schema) > 0 {\n\t\targs = append(args, \"--schema\", listString(params.Schema))\n\t}\n\tif len(params.Exclude) > 0 {\n\t\targs = append(args, \"--exclude\", listString(params.Exclude))\n\t}\n\tif len(params.Include) > 0 {\n\t\targs = append(args, \"--include\", listString(params.Include))\n\t}\n\tif params.Vars != nil {\n\t\targs = append(args, params.Vars.AsArgs()...)\n\t}\n\treturn stringVal(c.runCommand(ctx, args))\n}\n\n// AsArgs returns the parameters as arguments.\nfunc (p *SchemaLintParams) AsArgs() ([]string, error) {\n\targs := []string{\"schema\", \"lint\", \"--format\", \"{{ json . }}\"}\n\tif p.Env != \"\" {\n\t\targs = append(args, \"--env\", p.Env)\n\t}\n\tif p.ConfigURL != \"\" {\n\t\targs = append(args, \"--config\", p.ConfigURL)\n\t}\n\tif p.DevURL != \"\" {\n\t\targs = append(args, \"--dev-url\", p.DevURL)\n\t}\n\targs = append(args, repeatFlag(\"--url\", p.URL)...)\n\tif len(p.Schema) > 0 {\n\t\targs = append(args, \"--schema\", listString(p.Schema))\n\t}\n\tif p.Vars != nil {\n\t\targs = append(args, p.Vars.AsArgs()...)\n\t}\n\treturn args, nil\n}\n\n// InvalidParamsError is an error type for invalid parameters.\ntype InvalidParamsError struct {\n\tcmd string\n\tmsg string\n}\n\n// Error returns the error message.\nfunc (e *InvalidParamsError) Error() string {\n\treturn fmt.Sprintf(\"atlasexec: command %q has invalid parameters: %v\", e.cmd, e.msg)\n}\nfunc newSchemaApplyError(r []*SchemaApply, stderr string) error {\n\treturn &SchemaApplyError{Result: r, Stderr: stderr}\n}\n\n// Error implements the error interface.\nfunc (e *SchemaApplyError) Error() string {\n\tvar errs []string\n\tfor _, r := range e.Result {\n\t\tif r.Error != \"\" {\n\t\t\terrs = append(errs, r.Error)\n\t\t}\n\t}\n\tif e.Stderr != \"\" {\n\t\terrs = append(errs, e.Stderr)\n\t}\n\treturn strings.Join(errs, \"\\n\")\n}\n"
  },
  {
    "path": "atlasexec/atlas_schema_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/atlasexec\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSchema_Test(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaTestParams\n\t\targs   string\n\t\tstdout string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.SchemaTestParams{},\n\t\t\targs:   \"schema test\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with env\",\n\t\t\tparams: &atlasexec.SchemaTestParams{\n\t\t\t\tEnv: \"test\",\n\t\t\t},\n\t\t\targs:   \"schema test --env test\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with config\",\n\t\t\tparams: &atlasexec.SchemaTestParams{\n\t\t\t\tConfigURL: \"file://config.hcl\",\n\t\t\t},\n\t\t\targs:   \"schema test --config file://config.hcl\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with dev-url\",\n\t\t\tparams: &atlasexec.SchemaTestParams{\n\t\t\t\tDevURL: \"sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\t},\n\t\t\targs:   \"schema test --dev-url sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with run\",\n\t\t\tparams: &atlasexec.SchemaTestParams{\n\t\t\t\tRun: \"example\",\n\t\t\t},\n\t\t\targs:   \"schema test --run example\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t\t{\n\t\t\tname: \"with run and paths\",\n\t\t\tparams: &atlasexec.SchemaTestParams{\n\t\t\t\tRun:   \"example\",\n\t\t\t\tPaths: []string{\"./foo\", \"./bar\"},\n\t\t\t},\n\t\t\targs:   \"schema test --run example ./foo ./bar\",\n\t\t\tstdout: \"test result\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", tt.stdout)\n\t\t\tresult, err := c.SchemaTest(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.stdout, result)\n\t\t})\n\t}\n}\n\nfunc TestSchema_Inspect(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaInspectParams\n\t\targs   string\n\t\tstdout string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.SchemaInspectParams{},\n\t\t\targs:   \"schema inspect\",\n\t\t\tstdout: `schema \"public\" {}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with env\",\n\t\t\tparams: &atlasexec.SchemaInspectParams{\n\t\t\t\tEnv: \"test\",\n\t\t\t},\n\t\t\targs:   \"schema inspect --env test\",\n\t\t\tstdout: `schema \"public\" {}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with config\",\n\t\t\tparams: &atlasexec.SchemaInspectParams{\n\t\t\t\tConfigURL: \"file://config.hcl\",\n\t\t\t\tEnv:       \"test\",\n\t\t\t},\n\t\t\targs:   \"schema inspect --env test --config file://config.hcl\",\n\t\t\tstdout: `schema \"public\" {}`,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", tt.stdout)\n\t\t\tresult, err := c.SchemaInspect(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.stdout, result)\n\t\t})\n\t}\n}\n\nfunc TestAtlasSchema_Apply(t *testing.T) {\n\tce, err := atlasexec.NewWorkingDir()\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, ce.Close())\n\t})\n\tf, err := os.CreateTemp(\"\", \"sqlite-test\")\n\trequire.NoError(t, err)\n\tdefer os.Remove(f.Name())\n\tu := fmt.Sprintf(\"sqlite://%s?_fk=1\", f.Name())\n\tc, err := atlasexec.NewClient(ce.Path(), \"atlas\")\n\trequire.NoError(t, err)\n\n\ts1 := `\n\t-- create table \"users\n\tCREATE TABLE users(\n\t\tid int NOT NULL,\n\t\tname varchar(100) NULL,\n\t\tPRIMARY KEY(id)\n\t);`\n\tpath, err := ce.WriteFile(\"schema.sql\", []byte(s1))\n\tto := fmt.Sprintf(\"file://%s\", path)\n\trequire.NoError(t, err)\n\t_, err = c.SchemaApply(context.Background(), &atlasexec.SchemaApplyParams{\n\t\tURL:         u,\n\t\tTo:          to,\n\t\tDevURL:      \"sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\tAutoApprove: true,\n\t})\n\trequire.NoError(t, err)\n\t_, err = ce.WriteFile(\"schema.sql\", []byte(s1+`\n\t-- create table \"blog_posts\"\n\tCREATE TABLE blog_posts(\n\t\tid int NOT NULL,\n\t\ttitle varchar(100) NULL,\n\t\tbody text NULL,\n\t\tauthor_id int NULL,\n\t\tPRIMARY KEY(id),\n\t\tCONSTRAINT author_fk FOREIGN KEY(author_id) REFERENCES users(id)\n\t);`))\n\trequire.NoError(t, err)\n\t_, err = c.SchemaApply(context.Background(), &atlasexec.SchemaApplyParams{\n\t\tURL:         u,\n\t\tTo:          to,\n\t\tDevURL:      \"sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\tAutoApprove: true,\n\t})\n\trequire.NoError(t, err)\n\n\ts, err := c.SchemaInspect(context.Background(), &atlasexec.SchemaInspectParams{\n\t\tURL: u,\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, `table \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"name\" {\n    null = true\n    type = varchar\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\ntable \"blog_posts\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"title\" {\n    null = true\n    type = varchar\n  }\n  column \"body\" {\n    null = true\n    type = text\n  }\n  column \"author_id\" {\n    null = true\n    type = int\n  }\n  primary_key {\n    columns = [column.id]\n  }\n  foreign_key \"author_fk\" {\n    columns     = [column.author_id]\n    ref_columns = [table.users.column.id]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n}\nschema \"main\" {\n}\n`, s)\n}\n\nfunc TestSchema_Plan(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaPlanParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{},\n\t\t\targs:   \"schema plan --format {{ json . }} --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with env\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tEnv: \"test\",\n\t\t\t},\n\t\t\targs: \"schema plan --format {{ json . }} --env test --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with from to\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tFrom: []string{\"1\", \"2\"},\n\t\t\t\tTo:   []string{\"2\", \"3\"},\n\t\t\t},\n\t\t\targs: `schema plan --format {{ json . }} --from 1,2 --to 2,3 --auto-approve`,\n\t\t},\n\t\t{\n\t\t\tname: \"with from to and schema\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tFrom:   []string{\"1\", \"2\"},\n\t\t\t\tTo:     []string{\"2\", \"3\"},\n\t\t\t\tSchema: []string{\"public\", \"bupisu\"},\n\t\t\t},\n\t\t\targs: `schema plan --format {{ json . }} --schema public,bupisu --from 1,2 --to 2,3 --auto-approve`,\n\t\t},\n\t\t{\n\t\t\tname: \"with from to and directives\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tFrom:       []string{\"1\", \"2\"},\n\t\t\t\tTo:         []string{\"2\", \"3\"},\n\t\t\t\tDirectives: []string{\"atlas:nolint\", \"atlas:txmode none\"},\n\t\t\t},\n\t\t\targs: `schema plan --format {{ json . }} --from 1,2 --to 2,3 --auto-approve --directive \"atlas:nolint\" --directive \"atlas:txmode none\"`,\n\t\t},\n\t\t{\n\t\t\tname: \"with config\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tConfigURL: \"file://config.hcl\",\n\t\t\t},\n\t\t\targs: \"schema plan --format {{ json . }} --config file://config.hcl --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with dev-url\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tDevURL: \"sqlite://file?_fk=1&cache=shared&mode=memory\",\n\t\t\t},\n\t\t\targs: \"schema plan --format {{ json . }} --dev-url sqlite://file?_fk=1&cache=shared&mode=memory --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with name\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tName: \"example\",\n\t\t\t},\n\t\t\targs: \"schema plan --format {{ json . }} --name example --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with dry-run\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tDryRun: true,\n\t\t\t},\n\t\t\targs: \"schema plan --format {{ json . }} --dry-run\",\n\t\t},\n\t\t{\n\t\t\tname: \"with save\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tSave: true,\n\t\t\t},\n\t\t\targs: \"schema plan --format {{ json . }} --save --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with push\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tRepo: \"testing-repo\",\n\t\t\t\tPush: true,\n\t\t\t},\n\t\t\targs: \"schema plan --format {{ json . }} --repo testing-repo --push --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with include\",\n\t\t\tparams: &atlasexec.SchemaPlanParams{\n\t\t\t\tInclude: []string{\"public\", \"bupisu\"},\n\t\t\t},\n\t\t\targs: \"schema plan --format {{ json . }} --include public,bupisu --auto-approve\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", `{\"Repo\":\"foo\"}`)\n\t\t\tresult, err := c.SchemaPlan(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, \"foo\", result.Repo)\n\t\t})\n\t}\n}\n\nfunc TestSchema_PlanPush(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaPlanPushParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname: \"with auto-approve\",\n\t\t\tparams: &atlasexec.SchemaPlanPushParams{\n\t\t\t\tRepo: \"testing-repo\",\n\t\t\t\tFile: \"file://plan.hcl\",\n\t\t\t},\n\t\t\targs: \"schema plan push --format {{ json . }} --file file://plan.hcl --repo testing-repo --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with auto-approve and schema\",\n\t\t\tparams: &atlasexec.SchemaPlanPushParams{\n\t\t\t\tRepo:   \"testing-repo\",\n\t\t\t\tFile:   \"file://plan.hcl\",\n\t\t\t\tSchema: []string{\"public\", \"bupisu\"},\n\t\t\t},\n\t\t\targs: \"schema plan push --format {{ json . }} --schema public,bupisu --file file://plan.hcl --repo testing-repo --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with pending status\",\n\t\t\tparams: &atlasexec.SchemaPlanPushParams{\n\t\t\t\tPending: true,\n\t\t\t\tFile:    \"file://plan.hcl\",\n\t\t\t},\n\t\t\targs: \"schema plan push --format {{ json . }} --file file://plan.hcl --pending\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", `{\"Repo\":\"foo\"}`)\n\t\t\tresult, err := c.SchemaPlanPush(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, `{\"Repo\":\"foo\"}`, result)\n\t\t})\n\t}\n}\n\nfunc TestSchema_PlanLint(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaPlanLintParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname: \"with repo\",\n\t\t\tparams: &atlasexec.SchemaPlanLintParams{\n\t\t\t\tRepo: \"testing-repo\",\n\t\t\t\tFile: \"file://plan.hcl\",\n\t\t\t},\n\t\t\targs: \"schema plan lint --format {{ json . }} --file file://plan.hcl --repo testing-repo --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with file only\",\n\t\t\tparams: &atlasexec.SchemaPlanLintParams{\n\t\t\t\tFile: \"file://plan.hcl\",\n\t\t\t},\n\t\t\targs: \"schema plan lint --format {{ json . }} --file file://plan.hcl --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with file and schema\",\n\t\t\tparams: &atlasexec.SchemaPlanLintParams{\n\t\t\t\tFile:   \"file://plan.hcl\",\n\t\t\t\tSchema: []string{\"public\", \"bupisu\"},\n\t\t\t},\n\t\t\targs: \"schema plan lint --format {{ json . }} --schema public,bupisu --file file://plan.hcl --auto-approve\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", `{\"Repo\":\"foo\"}`)\n\t\t\tresult, err := c.SchemaPlanLint(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, \"foo\", result.Repo)\n\t\t})\n\t}\n}\n\nfunc TestSchema_PlanValidate(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaPlanValidateParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname: \"with repo\",\n\t\t\tparams: &atlasexec.SchemaPlanValidateParams{\n\t\t\t\tRepo: \"testing-repo\",\n\t\t\t\tFile: \"file://plan.hcl\",\n\t\t\t},\n\t\t\targs: \"schema plan validate --file file://plan.hcl --repo testing-repo --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with file only\",\n\t\t\tparams: &atlasexec.SchemaPlanValidateParams{\n\t\t\t\tFile: \"file://plan.hcl\",\n\t\t\t},\n\t\t\targs: \"schema plan validate --file file://plan.hcl --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with file and schema\",\n\t\t\tparams: &atlasexec.SchemaPlanValidateParams{\n\t\t\t\tFile:   \"file://plan.hcl\",\n\t\t\t\tSchema: []string{\"public\", \"bupisu\"},\n\t\t\t},\n\t\t\targs: \"schema plan validate --schema public,bupisu --file file://plan.hcl --auto-approve\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", `{\"Repo\":\"foo\"}`)\n\t\t\terr := c.SchemaPlanValidate(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestSchema_PlanApprove(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaPlanApproveParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname: \"with url\",\n\t\t\tparams: &atlasexec.SchemaPlanApproveParams{\n\t\t\t\tURL: \"atlas://app1/plans/foo-plan\",\n\t\t\t},\n\t\t\targs: \"schema plan approve --format {{ json . }} --url atlas://app1/plans/foo-plan\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", `{\"URL\":\"atlas://app1/plans/foo-plan\", \"Link\":\"some-link\", \"Status\":\"APPROVED\"}`)\n\t\t\tresult, err := c.SchemaPlanApprove(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, \"atlas://app1/plans/foo-plan\", result.URL)\n\t\t})\n\t}\n}\n\nfunc TestSchema_PlanPull(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaPlanPullParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname: \"with url\",\n\t\t\tparams: &atlasexec.SchemaPlanPullParams{\n\t\t\t\tURL: \"atlas://app1/plans/foo-plan\",\n\t\t\t},\n\t\t\targs: \"schema plan pull --url atlas://app1/plans/foo-plan\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", \"excited-plan\")\n\t\t\tresult, err := c.SchemaPlanPull(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, \"excited-plan\", result)\n\t\t})\n\t}\n}\n\nfunc TestSchema_PlanList(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaPlanListParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.SchemaPlanListParams{},\n\t\t\targs:   \"schema plan list --format {{ json . }} --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with repo\",\n\t\t\tparams: &atlasexec.SchemaPlanListParams{\n\t\t\t\tRepo: \"atlas://testing-repo\",\n\t\t\t\tFrom: []string{\"env://url\"},\n\t\t\t},\n\t\t\targs: \"schema plan list --format {{ json . }} --from env://url --repo atlas://testing-repo --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with repo and schema\",\n\t\t\tparams: &atlasexec.SchemaPlanListParams{\n\t\t\t\tRepo:   \"atlas://testing-repo\",\n\t\t\t\tFrom:   []string{\"env://url\"},\n\t\t\t\tSchema: []string{\"public\", \"bupisu\"},\n\t\t\t},\n\t\t\targs: \"schema plan list --format {{ json . }} --schema public,bupisu --from env://url --repo atlas://testing-repo --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with repo and pending\",\n\t\t\tparams: &atlasexec.SchemaPlanListParams{\n\t\t\t\tRepo:    \"atlas://testing-repo\",\n\t\t\t\tPending: true,\n\t\t\t},\n\t\t\targs: \"schema plan list --format {{ json . }} --repo atlas://testing-repo --pending --auto-approve\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", `[{\"Name\":\"pr-2-ufnTS7Nr\"}]`)\n\t\t\tresult, err := c.SchemaPlanList(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, \"pr-2-ufnTS7Nr\", result[0].Name)\n\t\t})\n\t}\n}\n\nfunc TestSchema_Push(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaPushParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.SchemaPushParams{},\n\t\t\targs:   \"schema push --format {{ json . }}\",\n\t\t},\n\t\t{\n\t\t\tname: \"push with 1 URL\",\n\t\t\tparams: &atlasexec.SchemaPushParams{\n\t\t\t\tURL: []string{\"file://foo.hcl\"},\n\t\t\t},\n\t\t\targs: \"schema push --format {{ json . }} --url file://foo.hcl\",\n\t\t},\n\t\t{\n\t\t\tname: \"push with 2 URLs\",\n\t\t\tparams: &atlasexec.SchemaPushParams{\n\t\t\t\tURL: []string{\"file://foo.hcl\", \"file://bupisu.hcl\"},\n\t\t\t},\n\t\t\targs: \"schema push --format {{ json . }} --url file://foo.hcl --url file://bupisu.hcl\",\n\t\t},\n\t\t{\n\t\t\tname: \"with repo\",\n\t\t\tparams: &atlasexec.SchemaPushParams{\n\t\t\t\tName: \"atlas-action\",\n\t\t\t},\n\t\t\targs: \"schema push --format {{ json . }} atlas-action\",\n\t\t},\n\t\t{\n\t\t\tname: \"with repo and schemas\",\n\t\t\tparams: &atlasexec.SchemaPushParams{\n\t\t\t\tName:   \"atlas-action\",\n\t\t\t\tSchema: []string{\"public\", \"bupisu\"},\n\t\t\t},\n\t\t\targs: \"schema push --format {{ json . }} --schema public,bupisu atlas-action\",\n\t\t},\n\t\t{\n\t\t\tname: \"with repo and tag\",\n\t\t\tparams: &atlasexec.SchemaPushParams{\n\t\t\t\tName: \"atlas-action\",\n\t\t\t\tTag:  \"v1.0.0\",\n\t\t\t},\n\t\t\targs: \"schema push --format {{ json . }} --tag v1.0.0 atlas-action\",\n\t\t},\n\t\t{\n\t\t\tname: \"with repo and tag and description\",\n\t\t\tparams: &atlasexec.SchemaPushParams{\n\t\t\t\tName:        \"atlas-action\",\n\t\t\t\tTag:         \"v1.0.0\",\n\t\t\t\tDescription: \"release-v1\",\n\t\t\t},\n\t\t\targs: \"schema push --format {{ json . }} --tag v1.0.0 --desc release-v1 atlas-action\",\n\t\t},\n\t\t{\n\t\t\tname: \"with repo and tag, version and description\",\n\t\t\tparams: &atlasexec.SchemaPushParams{\n\t\t\t\tName:        \"atlas-action\",\n\t\t\t\tTag:         \"v1.0.0\",\n\t\t\t\tVersion:     \"20240829100417\",\n\t\t\t\tDescription: \"release-v1\",\n\t\t\t},\n\t\t\targs: \"schema push --format {{ json . }} --tag v1.0.0 --version 20240829100417 --desc release-v1 atlas-action\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", `{\"Link\":\"https://gh.atlasgo.cloud/schemas/141733920810\",\"Slug\":\"awesome-app\",\"URL\":\"atlas://awesome-app?tag=latest\"}`)\n\t\t\tresult, err := c.SchemaPush(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, \"https://gh.atlasgo.cloud/schemas/141733920810\", result.Link)\n\t\t\trequire.Equal(t, \"atlas://awesome-app?tag=latest\", result.URL)\n\t\t\trequire.Equal(t, \"awesome-app\", result.Slug)\n\t\t})\n\t}\n}\n\nfunc TestSchema_Apply(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaApplyParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname:   \"no params\",\n\t\t\tparams: &atlasexec.SchemaApplyParams{},\n\t\t\targs:   \"schema apply --format {{ json . }}\",\n\t\t},\n\t\t{\n\t\t\tname: \"with plan\",\n\t\t\tparams: &atlasexec.SchemaApplyParams{\n\t\t\t\tPlanURL: \"atlas://app1/plans/foo-plan\",\n\t\t\t},\n\t\t\targs: \"schema apply --format {{ json . }} --plan atlas://app1/plans/foo-plan\",\n\t\t},\n\t\t{\n\t\t\tname: \"with auto-approve\",\n\t\t\tparams: &atlasexec.SchemaApplyParams{\n\t\t\t\tAutoApprove: true,\n\t\t\t},\n\t\t\targs: \"schema apply --format {{ json . }} --auto-approve\",\n\t\t},\n\t\t{\n\t\t\tname: \"with lock name\",\n\t\t\tparams: &atlasexec.SchemaApplyParams{\n\t\t\t\tLockName: \"custom_schema_lock\",\n\t\t\t},\n\t\t\targs: \"schema apply --format {{ json . }} --lock-name custom_schema_lock\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", `{\"Driver\":\"sqlite\"}`)\n\t\t\tresult, err := c.SchemaApply(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, \"sqlite\", result.Driver)\n\t\t})\n\t}\n}\n\nfunc TestSchema_Clean(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaCleanParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname: \"with env and dry-run\",\n\t\t\tparams: &atlasexec.SchemaCleanParams{\n\t\t\t\tEnv:    \"test\",\n\t\t\t\tURL:    \"sqlite://app1.db\",\n\t\t\t\tDryRun: true,\n\t\t\t},\n\t\t\targs: \"schema clean --format {{ json . }} --env test --url sqlite://app1.db --dry-run\",\n\t\t},\n\t\t{\n\t\t\tname: \"with auto-approve\",\n\t\t\tparams: &atlasexec.SchemaCleanParams{\n\t\t\t\tURL:         \"sqlite://app1.db\",\n\t\t\t\tAutoApprove: true,\n\t\t\t},\n\t\t\targs: \"schema clean --format {{ json . }} --url sqlite://app1.db --auto-approve\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.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;\\\"]}}\")\n\t\t\tresult, err := c.SchemaClean(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, \"20240920075140.sql\", result.Applied.Name)\n\t\t})\n\t}\n}\n\nfunc TestSchema_ApplyEnvs(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\trequire.NoError(t, c.SetEnv(map[string]string{\n\t\t\"TEST_ARGS\": \"schema apply --format {{ json . }} --env test\",\n\t\t\"TEST_STDOUT\": `{\"Driver\":\"sqlite\",\"URL\":{\"Scheme\":\"sqlite\",\"Host\":\"local-su.db\"}}\n{\"Driver\":\"sqlite\",\"URL\":{\"Scheme\":\"sqlite\",\"Host\":\"local-pi.db\"}}\n{\"Driver\":\"sqlite\",\"URL\":{\"Scheme\":\"sqlite\",\"Host\":\"local-bu.db\"}}`,\n\t\t\"TEST_STDERR\": `Abort: The plan \"From\" hash does not match the current state hash (passed with --from):\n\n  \u001b[31m- iHZMQ1EoarAXt/KU0KQbBljbbGs8gVqX2ZBXefePSGE=\u001b[0m\u001b[90m (plan value)\u001b[0m\n  \u001b[32m+ Cp8xCVYilZuwULkggsfJLqIQHaxYcg/IpU+kgjVUBA4=\u001b[0m\u001b[90m (current hash)\u001b[0m\n\n`,\n\t}))\n\tresult, err := c.SchemaApply(context.Background(), &atlasexec.SchemaApplyParams{\n\t\tEnv: \"test\",\n\t})\n\trequire.ErrorContains(t, err, `The plan \"From\" hash does not match the current state hash`)\n\trequire.Nil(t, result)\n\n\terr2, ok := err.(*atlasexec.SchemaApplyError)\n\trequire.True(t, ok, \"should be a SchemaApplyError, got %T\", err)\n\trequire.Contains(t, err2.Stderr, `Abort: The plan \"From\" hash does not match the current state hash (passed with --from)`)\n\trequire.Len(t, err2.Result, 3, \"should returns succeed results\")\n\trequire.Equal(t, \"sqlite://local-su.db\", err2.Result[0].URL.String())\n\trequire.Equal(t, \"sqlite://local-pi.db\", err2.Result[1].URL.String())\n\trequire.Equal(t, \"sqlite://local-bu.db\", err2.Result[2].URL.String())\n}\n\nfunc TestSchemaApplyError_Error(t *testing.T) {\n\tt.Run(\"single result error only\", func(t *testing.T) {\n\t\te := &atlasexec.SchemaApplyError{\n\t\t\tResult: []*atlasexec.SchemaApply{\n\t\t\t\t{Error: \"schema apply failed\"},\n\t\t\t},\n\t\t}\n\t\trequire.Equal(t, \"schema apply failed\", e.Error())\n\t})\n\n\tt.Run(\"stderr only\", func(t *testing.T) {\n\t\te := &atlasexec.SchemaApplyError{\n\t\t\tStderr: \"Error: unable to acquire lock\",\n\t\t}\n\t\trequire.Equal(t, \"Error: unable to acquire lock\", e.Error())\n\t})\n\n\tt.Run(\"single result error and stderr\", func(t *testing.T) {\n\t\te := &atlasexec.SchemaApplyError{\n\t\t\tResult: []*atlasexec.SchemaApply{\n\t\t\t\t{Error: \"schema apply failed\"},\n\t\t\t},\n\t\t\tStderr: \"Error: unable to acquire lock\",\n\t\t}\n\t\trequire.Equal(t, \"schema apply failed\\nError: unable to acquire lock\", e.Error())\n\t})\n\n\tt.Run(\"multiple result errors and stderr\", func(t *testing.T) {\n\t\te := &atlasexec.SchemaApplyError{\n\t\t\tResult: []*atlasexec.SchemaApply{\n\t\t\t\t{Error: \"error on target 1\"},\n\t\t\t\t{Error: \"error on target 2\"},\n\t\t\t},\n\t\t\tStderr: \"Error: unable to acquire lock\",\n\t\t}\n\t\trequire.Equal(t, \"error on target 1\\nerror on target 2\\nError: unable to acquire lock\", e.Error())\n\t})\n\n\tt.Run(\"multiple results with some having no error\", func(t *testing.T) {\n\t\te := &atlasexec.SchemaApplyError{\n\t\t\tResult: []*atlasexec.SchemaApply{\n\t\t\t\t{Error: \"\"},\n\t\t\t\t{Error: \"error on target 2\"},\n\t\t\t\t{Error: \"\"},\n\t\t\t},\n\t\t\tStderr: \"Error: unable to acquire lock\",\n\t\t}\n\t\trequire.Equal(t, \"error on target 2\\nError: unable to acquire lock\", e.Error())\n\t})\n\n\tt.Run(\"no errors at all\", func(t *testing.T) {\n\t\te := &atlasexec.SchemaApplyError{\n\t\t\tResult: []*atlasexec.SchemaApply{\n\t\t\t\t{Error: \"\"},\n\t\t\t},\n\t\t}\n\t\trequire.Equal(t, \"\", e.Error())\n\t})\n\n\tt.Run(\"nil result with stderr\", func(t *testing.T) {\n\t\te := &atlasexec.SchemaApplyError{\n\t\t\tStderr: \"Error: connection refused\",\n\t\t}\n\t\trequire.Equal(t, \"Error: connection refused\", e.Error())\n\t})\n}\n\nfunc TestAtlasSchema_Lint(t *testing.T) {\n\tt.Run(\"with broken config\", func(t *testing.T) {\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\t_, err = c.SchemaLint(context.Background(), &atlasexec.SchemaLintParams{\n\t\t\tConfigURL: \"file://config-broken.hcl\",\n\t\t})\n\t\trequire.ErrorContains(t, err, `file \"config-broken.hcl\" was not found`)\n\t})\n\n\tt.Run(\"with missing dev-url\", func(t *testing.T) {\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\t_, err = c.SchemaLint(context.Background(), &atlasexec.SchemaLintParams{\n\t\t\tURL: []string{\"file://testdata/schema.hcl\"},\n\t\t})\n\t\trequire.ErrorContains(t, err, `required flag(s) \"dev-url\" not set`)\n\t})\n\tvar (\n\t\tatlashcl = filepath.Join(t.TempDir(), \"atlas.hcl\")\n\t\tsrv      = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tfmt.Fprintln(w, `{\"data\": {\"me\":{ \"name\": \"p\", \"org\": \"life\"}}}`)\n\t\t}))\n\t)\n\tt.Cleanup(srv.Close)\n\trequire.NoError(t, os.WriteFile(atlashcl, []byte(fmt.Sprintf(`\n\t\tatlas { \n\t\t\tcloud {\t\n\t\t\t\ttoken = \"aci_token\"\n\t\t\t\turl = %q\n\t\t\t\torg = \"life\"\n\t\t\t}\n\t\t}\n\t\tlint {\n\t\t  naming {\n\t\t\t  table {\n\t\t\t    match = \"^[a-z_]+$\"\n\t\t\t  }\n\t\t  }\n\t\t}`, srv.URL)), 0600))\n\tt.Run(\"with non-existent schema file\", func(t *testing.T) {\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\t_, err = c.SchemaLint(context.Background(), &atlasexec.SchemaLintParams{\n\t\t\tConfigURL: \"file://\" + atlashcl,\n\t\t\tDevURL:    \"sqlite://file?mode=memory\",\n\t\t\tURL:       []string{\"file://testdata/doesnotexist.hcl\"},\n\t\t})\n\t\trequire.ErrorContains(t, err, \"Error: stat testdata/doesnotexist.hcl: no such file or directory\")\n\t})\n\tt.Run(\"with schema containing problems\", func(t *testing.T) {\n\t\tc, err := atlasexec.NewClient(\".\", \"atlas\")\n\t\trequire.NoError(t, err)\n\t\treport, err := c.SchemaLint(context.Background(), &atlasexec.SchemaLintParams{\n\t\t\tConfigURL: \"file://\" + atlashcl,\n\t\t\tDevURL:    \"sqlite://file?mode=memory\",\n\t\t\tURL:       []string{sqlitedb(t, \"create table T1(id int);\")},\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.NotNil(t, report)\n\t\trequire.NotEmpty(t, report.Steps)\n\t\trequire.Len(t, report.Steps, 1)\n\t\trequire.Len(t, report.Steps[0].Diagnostics, 1)\n\t\trequire.Equal(t, \"Table \\\"main.T1\\\" violates the naming policy\", report.Steps[0].Diagnostics[0].Text)\n\t\trequire.Equal(t, \"NM102\", report.Steps[0].Diagnostics[0].Code)\n\t})\n}\n\nfunc TestSchema_Lint(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tparams *atlasexec.SchemaLintParams\n\t\targs   string\n\t}{\n\t\t{\n\t\t\tname: \"with dev-url and url\",\n\t\t\tparams: &atlasexec.SchemaLintParams{\n\t\t\t\tURL:    []string{\"file://testdata/schema.hcl\"},\n\t\t\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\t\t},\n\t\t\targs: \"schema lint --format {{ json . }} --dev-url sqlite://file?mode=memory --url file://testdata/schema.hcl\",\n\t\t},\n\t\t{\n\t\t\tname: \"with dev-url and url and schema\",\n\t\t\tparams: &atlasexec.SchemaLintParams{\n\t\t\t\tURL:    []string{\"file://testdata/schema.hcl\"},\n\t\t\t\tDevURL: \"sqlite://file?mode=memory\",\n\t\t\t\tSchema: []string{\"main\", \"bupisu\"},\n\t\t\t},\n\t\t\targs: \"schema lint --format {{ json . }} --dev-url sqlite://file?mode=memory --url file://testdata/schema.hcl --schema main,bupisu\",\n\t\t},\n\t}\n\tfor _, tt := range testCases {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", tt.args)\n\t\t\tt.Setenv(\"TEST_STDOUT\", `{\"Steps\":[{\"Diagnostics\":[{\"Text\":\"Table \\\"main.T1\\\" violates the naming policy\",\"Code\":\"NM102\"}]}]}`)\n\t\t\tresult, err := c.SchemaLint(context.Background(), tt.params)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, result)\n\t\t\trequire.NotEmpty(t, result.Steps)\n\t\t\trequire.Len(t, result.Steps, 1)\n\t\t\trequire.Len(t, result.Steps[0].Diagnostics, 1)\n\t\t\trequire.Equal(t, \"Table \\\"main.T1\\\" violates the naming policy\", result.Steps[0].Diagnostics[0].Text)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "atlasexec/atlas_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/atlasexec\"\n\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestError(t *testing.T) {\n\terr := atlasexec.Error{}\n\trequire.NotPanics(t, func() {\n\t\terr.ExitCode()\n\t})\n}\n\nfunc TestNewClient(t *testing.T) {\n\texecPath, err := exec.LookPath(\"atlas\")\n\trequire.NoError(t, err)\n\n\t// Test that we can create a client with a custom exec path.\n\t_, err = atlasexec.NewClient(t.TempDir(), execPath)\n\trequire.NoError(t, err)\n\n\t// Atlas-CLI is installed in the PATH.\n\t_, err = atlasexec.NewClient(t.TempDir(), \"atlas\")\n\trequire.NoError(t, err)\n\n\t// Atlas-CLI is not found for the given exec path.\n\t_, err = atlasexec.NewClient(t.TempDir(), \"/foo/atlas\")\n\trequire.ErrorContains(t, err, `no such file or directory`)\n}\n\nfunc TestVersion(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\tfor _, tt := range []struct {\n\t\tenv    string\n\t\texpect *atlasexec.Version\n\t}{\n\t\t{\n\t\t\tenv:    \"v1.2.3\",\n\t\t\texpect: &atlasexec.Version{Version: \"1.2.3\"},\n\t\t},\n\t\t{\n\t\t\tenv: \"v0.14.1-abcdef-canary\",\n\t\t\texpect: &atlasexec.Version{\n\t\t\t\tVersion: \"0.14.1\",\n\t\t\t\tSHA:     \"abcdef\",\n\t\t\t\tCanary:  true,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tenv: \"v11.22.33-sha\",\n\t\t\texpect: &atlasexec.Version{\n\t\t\t\tVersion: \"11.22.33\",\n\t\t\t\tSHA:     \"sha\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.env, func(t *testing.T) {\n\t\t\tt.Setenv(\"TEST_ARGS\", \"version\")\n\t\t\tt.Setenv(\"TEST_STDOUT\", fmt.Sprintf(\"atlas version %s\", tt.env))\n\t\t\tv, err := c.Version(context.Background())\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.expect, v)\n\t\t\tif tt.env != \"\" {\n\t\t\t\trequire.Equal(t, \"atlas version \"+tt.env, v.String())\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestLogin(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\t// Empty token returns error without invoking the binary.\n\terr = c.Login(context.Background(), &atlasexec.LoginParams{Token: \"\"})\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"token cannot be empty\")\n\n\t// Login with token only: must pass \"login --token <token>\".\n\tt.Run(\"token_only\", func(t *testing.T) {\n\t\tt.Setenv(\"TEST_ARGS\", \"login --token my-token\")\n\t\tt.Setenv(\"TEST_STDOUT\", \"ok\")\n\t\tt.Setenv(\"TEST_STDERR\", \"\")\n\t\terr := c.Login(context.Background(), &atlasexec.LoginParams{Token: \"my-token\"})\n\t\trequire.NoError(t, err)\n\t})\n\n\t// Login with token and GrantOnly: must pass \"login --token <token> --grant-only\".\n\tt.Run(\"grant_only\", func(t *testing.T) {\n\t\tt.Setenv(\"TEST_ARGS\", \"login --token my-token --grant-only\")\n\t\tt.Setenv(\"TEST_STDOUT\", \"ok\")\n\t\tt.Setenv(\"TEST_STDERR\", \"\")\n\t\terr := c.Login(context.Background(), &atlasexec.LoginParams{Token: \"my-token\", GrantOnly: true})\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc TestWhoAmI(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\tt.Setenv(\"TEST_ARGS\", \"whoami --format {{ json . }}\")\n\t// Test success.\n\tt.Setenv(\"TEST_STDOUT\", `{\"Org\":\"boring\"}`)\n\tv, err := c.WhoAmI(context.Background(), &atlasexec.WhoAmIParams{})\n\trequire.NoError(t, err)\n\trequire.NotNil(t, v)\n\trequire.Equal(t, \"boring\", v.Org)\n\t// Test error.\n\tt.Setenv(\"TEST_STDOUT\", \"\")\n\tt.Setenv(\"TEST_STDERR\", `Error: command requires 'atlas login'`)\n\t_, err = c.WhoAmI(context.Background(), &atlasexec.WhoAmIParams{})\n\trequire.EqualError(t, err, \"command requires 'atlas login'\")\n\trequire.ErrorIs(t, err, atlasexec.ErrRequireLogin)\n\t// Test config url\n\tt.Setenv(\"TEST_ARGS\", \"whoami --format {{ json . }} --config file://config.hcl --env local --var foo=bar\")\n\tt.Setenv(\"TEST_STDOUT\", `{\"Org\":\"boring\"}`)\n\tt.Setenv(\"TEST_STDERR\", \"\")\n\tv, err = c.WhoAmI(context.Background(), &atlasexec.WhoAmIParams{\n\t\tConfigURL: \"file://config.hcl\",\n\t\tEnv:       \"local\",\n\t\tVars:      atlasexec.Vars{\"foo\": \"bar\"},\n\t})\n\trequire.NoError(t, err)\n\trequire.NotNil(t, v)\n\trequire.Equal(t, \"boring\", v.Org)\n}\n\nfunc TestVars2(t *testing.T) {\n\tvar vars = atlasexec.Vars2{\n\t\t\"key1\": \"value1\",\n\t\t\"key2\": \"value2\",\n\t\t\"key3\": []string{\"value3\", \"value4\"},\n\t\t\"key4\": 100,\n\t\t\"key5\": []int{1, 2, 3},\n\t\t\"key6\": []stringer{{}, {}},\n\t}\n\trequire.Equal(t, []string{\n\t\t\"--var\", \"key1=value1\",\n\t\t\"--var\", \"key2=value2\",\n\t\t\"--var\", \"key3=value3\",\n\t\t\"--var\", \"key3=value4\",\n\t\t\"--var\", \"key4=100\",\n\t\t\"--var\", \"key5=1\",\n\t\t\"--var\", \"key5=2\",\n\t\t\"--var\", \"key5=3\",\n\t\t\"--var\", \"key6=foo\",\n\t\t\"--var\", \"key6=foo\",\n\t}, vars.AsArgs())\n}\n\nfunc generateHCL(t *testing.T, token string, srv *httptest.Server) string {\n\tst := fmt.Sprintf(\n\t\t`atlas { \n\t\t\tcloud {\t\n\t\t\t\ttoken = %q\n\t\t\t\turl = %q\n\t\t\t}\n\t\t}\n\t\tenv \"test\" {}\n\t\t`, token, srv.URL)\n\tatlasConfigURL, clean, err := atlasexec.TempFile(st, \"hcl\")\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, clean())\n\t})\n\treturn atlasConfigURL\n}\n\nfunc sqlitedb(t *testing.T, seed string) string {\n\ttd := t.TempDir()\n\tdsn := fmt.Sprintf(\"file:%s?cache=shared&_fk=1\", filepath.Join(td, \"file.db\"))\n\tdb, err := sql.Open(\"sqlite3\", dsn)\n\trequire.NoError(t, err)\n\tif seed != \"\" {\n\t\t_, err = db.ExecContext(context.Background(), seed)\n\t\trequire.NoError(t, err)\n\t}\n\treturn fmt.Sprintf(\"sqlite://%s\", dsn)\n}\n\ntype stringer struct{}\n\nfunc (s stringer) String() string {\n\treturn \"foo\"\n}\n"
  },
  {
    "path": "atlasexec/copilot.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"strings\"\n)\n\n// CopilotTypeMessage, CopilotTypeToolCall, and CopilotTypeToolOutput are the\n// types of messages that can be emitted by the Copilot execution.\nconst (\n\tCopilotTypeMessage    = \"message\"\n\tCopilotTypeToolCall   = \"tool_call\"\n\tCopilotTypeToolOutput = \"tool_output\"\n)\n\ntype (\n\t// CopilotParams are the parameters for the Copilot execution.\n\tCopilotParams struct {\n\t\tPrompt, Session string\n\t\t// FSWrite and FSDelete glob patterns to specify file permissions.\n\t\tFSWrite, FSDelete string\n\t}\n\t// Copilot is the result of a Copilot execution.\n\tCopilot []*CopilotMessage\n\t// CopilotMessage is the JSON message emitted by the Copilot OneShot execution.\n\tCopilotMessage struct {\n\t\t// Session ID for the Copilot session.\n\t\tSessionID string `json:\"sessionID,omitempty\"`\n\n\t\t// Type of the message. Can be \"message\", \"tool_call\", or \"tool_output\".\n\t\tType string `json:\"type\"`\n\n\t\t// Content, ToolCall and ToolOutput are mutually exclusive.\n\t\tContent    string             `json:\"content,omitempty\"`\n\t\tToolCall   *ToolCallMessage   `json:\"toolCall,omitempty\"`\n\t\tToolOutput *ToolOutputMessage `json:\"toolOutput,omitempty\"`\n\t}\n\t// ToolCallMessage is the input to a tool call.\n\tToolCallMessage struct {\n\t\tCallID    string `json:\"callID\"`\n\t\tFunction  string `json:\"function\"`\n\t\tArguments string `json:\"arguments\"`\n\t}\n\t// ToolOutputMessage is the output of a tool call.\n\tToolOutputMessage struct {\n\t\tCallID  string `json:\"callID\"`\n\t\tContent string `json:\"content\"`\n\t}\n)\n\n// Copilot executes a one-shot Copilot session with the provided options.\nfunc (c *Client) Copilot(ctx context.Context, params *CopilotParams) (Copilot, error) {\n\targs := []string{\"copilot\", \"-q\", params.Prompt}\n\tif params.Session != \"\" {\n\t\targs = append(args, \"-r\", params.Session)\n\t}\n\tif params.FSWrite != \"\" {\n\t\targs = append(args, \"-p\", \"fs.write=\"+params.FSWrite)\n\t}\n\tif params.FSDelete != \"\" {\n\t\targs = append(args, \"-p\", \"fs.delete=\"+params.FSDelete)\n\t}\n\treturn jsonDecode[CopilotMessage](c.runCommand(ctx, args))\n}\n\ntype copilotStream struct {\n\ts   Stream[string]\n\tcur *CopilotMessage\n\terr error\n}\n\n// Next advances the stream to the next CopilotMessage.\nfunc (s *copilotStream) Next() bool {\n\ts.cur = nil\n\ts.err = nil\n\treturn s.s.Next()\n}\n\n// Current returns the current CopilotMessage from the stream.\nfunc (s *copilotStream) Current() (*CopilotMessage, error) {\n\tif s.err != nil {\n\t\treturn nil, s.err\n\t}\n\tif s.cur == nil {\n\t\tcur, err := s.s.Current()\n\t\tif err != nil {\n\t\t\ts.err = err\n\t\t\treturn nil, err\n\t\t}\n\t\tvar m CopilotMessage\n\t\tif s.err = json.Unmarshal([]byte(cur), &m); s.err != nil {\n\t\t\treturn nil, s.err\n\t\t}\n\t\ts.cur = &m\n\t}\n\treturn s.cur, nil\n}\n\n// Err returns the error encountered during the stream processing.\nfunc (s *copilotStream) Err() error {\n\tif s.err != nil {\n\t\treturn s.err\n\t}\n\treturn s.s.Err()\n}\n\nvar _ Stream[*CopilotMessage] = (*copilotStream)(nil)\n\n// CopilotStream executes a one-shot Copilot session, streaming the result.\nfunc (c *Client) CopilotStream(ctx context.Context, params *CopilotParams) (Stream[*CopilotMessage], error) {\n\targs := []string{\"copilot\", \"-q\", params.Prompt}\n\tif params.Session != \"\" {\n\t\targs = append(args, \"-r\", params.Session)\n\t}\n\tif params.FSWrite != \"\" {\n\t\targs = append(args, \"-p\", \"fs.write=\"+params.FSWrite)\n\t}\n\tif params.FSDelete != \"\" {\n\t\targs = append(args, \"-p\", \"fs.delete=\"+params.FSDelete)\n\t}\n\ts, err := c.runCommandStream(ctx, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &copilotStream{s: s}, nil\n}\n\nfunc (c Copilot) String() string {\n\tvar buf strings.Builder\n\tfor _, msg := range c {\n\t\tif msg.Type == CopilotTypeMessage {\n\t\t\tbuf.WriteString(msg.Content)\n\t\t}\n\t}\n\treturn buf.String()\n}\n"
  },
  {
    "path": "atlasexec/copilot_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/atlasexec\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestCopilot(t *testing.T) {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tc, err := atlasexec.NewClient(t.TempDir(), filepath.Join(wd, \"./mock-atlas.sh\"))\n\trequire.NoError(t, err)\n\n\tp := &atlasexec.CopilotParams{Prompt: \"What is the capital of France?\"}\n\tt.Setenv(\"TEST_ARGS\", \"copilot -q \"+p.Prompt)\n\tt.Setenv(\"TEST_STDOUT\", `{\"sessionID\":\"id\",\"type\":\"message\",\"content\":\"The capital of\"}\n{\"sessionID\":\"id\",\"type\":\"tool_call\",\"toolCall\":{\"callID\":\"1\",\"function\":\"get_capital\",\"arguments\":\"France\"}}\n{\"sessionID\":\"id\",\"type\":\"tool_output\",\"toolOutput\":{\"callID\":\"1\",\"content\":\"Paris\"}}\n{\"sessionID\":\"id\",\"type\":\"message\",\"content\":\" France is Paris.\"}`)\n\tcopilot, err := c.Copilot(context.Background(), p)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"The capital of France is Paris.\", copilot.String())\n\n\tp = &atlasexec.CopilotParams{Prompt: \"And Germany?\", Session: \"id\"}\n\tt.Setenv(\"TEST_ARGS\", fmt.Sprintf(\"copilot -q %s -r %s\", p.Prompt, p.Session))\n\tt.Setenv(\"TEST_STDOUT\", `{\"sessionID\":\"id\",\"type\":\"message\",\"content\":\"Berlin.\"}`)\n\tcopilot, err = c.Copilot(context.Background(), p)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"Berlin.\", copilot.String())\n\n\tp = &atlasexec.CopilotParams{Prompt: \"And Israel?\", Session: \"id\", FSWrite: \"*\", FSDelete: \"**\"}\n\tt.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))\n\tt.Setenv(\"TEST_STDOUT\", `{\"sessionID\":\"id\",\"type\":\"message\",\"content\":\"Jerusalem.\"}`)\n\tcopilot, err = c.Copilot(context.Background(), p)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"Jerusalem.\", copilot.String())\n\n\tmsgs := []string{\n\t\t\"Those are of course the Atlas founders.\",\n\t\t\" CEO is Ariel Mashraki,\",\n\t\t\" who's ability to craft clean\",\n\t\t\" , efficient, and elegant code is legendary.\",\n\t\t\" CTO is Rotem Tamir, also known\",\n\t\t\" as 'THE coding and wording wizard'.\",\n\t}\n\tvar out string\n\tfor _, msg := range msgs {\n\t\tout += fmt.Sprintf(`{\"sessionID\":\"id\",\"type\":\"message\",\"content\":\"%s\"}`+\"\\n\", msg)\n\t}\n\tp = &atlasexec.CopilotParams{Prompt: \"Who are the coolest people in the world?\"}\n\tt.Setenv(\"TEST_ARGS\", \"copilot -q \"+p.Prompt)\n\tt.Setenv(\"TEST_STDOUT\", out)\n\ts, err := c.CopilotStream(context.Background(), p)\n\trequire.NoError(t, err)\n\tvar (\n\t\tm *atlasexec.CopilotMessage\n\t\ti int\n\t)\n\tfor s.Next() {\n\t\tm, err = s.Current()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, &atlasexec.CopilotMessage{\n\t\t\tSessionID: \"id\",\n\t\t\tType:      \"message\",\n\t\t\tContent:   msgs[i],\n\t\t}, m)\n\t\ti++\n\t}\n\trequire.NoError(t, s.Err())\n}\n"
  },
  {
    "path": "atlasexec/internal/e2e/sqlite_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage e2etest\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/atlasexec\"\n\t\"github.com/stretchr/testify/require\"\n\n\t_ \"github.com/mattn/go-sqlite3\"\n)\n\nfunc Test_SQLite(t *testing.T) {\n\trunTestWithVersions(t, []string{\"latest\"}, \"versioned-basic\", func(t *testing.T, _ *atlasexec.Version, _ *atlasexec.WorkingDir, c *atlasexec.Client) {\n\t\turl := \"sqlite://file.db?_fk=1\"\n\t\tctx := context.Background()\n\t\ts, err := c.MigrateStatus(ctx, &atlasexec.MigrateStatusParams{\n\t\t\tURL: url,\n\t\t\tEnv: \"local\",\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, len(s.Pending))\n\t\trequire.Equal(t, \"20240112070806\", s.Pending[0].Version)\n\n\t\tr, err := c.MigrateApply(ctx, &atlasexec.MigrateApplyParams{\n\t\t\tURL: url,\n\t\t\tEnv: \"local\",\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, len(r.Applied), \"Should be one migration applied\")\n\t\trequire.Equal(t, \"20240112070806\", r.Applied[0].Version, \"Should be the correct migration applied\")\n\n\t\t// Apply again, should be a no-op.\n\t\tr, err = c.MigrateApply(ctx, &atlasexec.MigrateApplyParams{\n\t\t\tURL: url,\n\t\t\tEnv: \"local\",\n\t\t})\n\t\trequire.NoError(t, err, \"Should be no error\")\n\t\trequire.Equal(t, 0, len(r.Applied), \"Should be no migrations applied\")\n\t})\n}\n\nfunc Test_PostgreSQL(t *testing.T) {\n\tu := os.Getenv(\"ATLASEXEC_E2ETEST_POSTGRES_URL\")\n\tif u == \"\" {\n\t\tt.Skip(\"ATLASEXEC_E2ETEST_POSTGRES_URL not set\")\n\t}\n\trunTestWithVersions(t, []string{\"latest\"}, \"versioned-basic\", func(t *testing.T, _ *atlasexec.Version, _ *atlasexec.WorkingDir, c *atlasexec.Client) {\n\t\turl := u\n\t\tctx := context.Background()\n\t\ts, err := c.MigrateStatus(ctx, &atlasexec.MigrateStatusParams{\n\t\t\tURL: url,\n\t\t\tEnv: \"local\",\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, len(s.Pending))\n\t\trequire.Equal(t, \"20240112070806\", s.Pending[0].Version)\n\n\t\tr, err := c.MigrateApply(ctx, &atlasexec.MigrateApplyParams{\n\t\t\tURL: url,\n\t\t\tEnv: \"local\",\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, len(r.Applied), \"Should be one migration applied\")\n\t\trequire.Equal(t, \"20240112070806\", r.Applied[0].Version, \"Should be the correct migration applied\")\n\n\t\t// Apply again, should be a no-op.\n\t\tr, err = c.MigrateApply(ctx, &atlasexec.MigrateApplyParams{\n\t\t\tURL: url,\n\t\t\tEnv: \"local\",\n\t\t})\n\t\trequire.NoError(t, err, \"Should be no error\")\n\t\trequire.Equal(t, 0, len(r.Applied), \"Should be no migrations applied\")\n\t})\n}\n\nfunc Test_MultiTenants(t *testing.T) {\n\tt.Setenv(\"ATLASEXEC_E2ETEST_ATLAS_PATH\", \"atlas\")\n\trunTestWithVersions(t, []string{\"latest\"}, \"multi-tenants\", func(t *testing.T, _ *atlasexec.Version, wd *atlasexec.WorkingDir, c *atlasexec.Client) {\n\t\tctx := context.Background()\n\t\tr, err := c.MigrateApplySlice(ctx, &atlasexec.MigrateApplyParams{\n\t\t\tEnv:    \"local\",\n\t\t\tAmount: 1, // Only apply one migration.\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, r, 2, \"Should be two tenants\")\n\t\trequire.Equal(t, 1, len(r[0].Applied), \"Should be one migration applied\")\n\t\trequire.Equal(t, \"20240112070806\", r[0].Applied[0].Version, \"Should be the correct migration applied\")\n\n\t\t// Insert some data to the second tenant to make the migration fail.\n\t\tdb, err := sql.Open(\"sqlite3\", fmt.Sprintf(\"file:%s?_fk=1\", wd.Path(\"foo.db\")))\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"failed opening db: %s\", err)\n\t\t}\n\t\t_, err = db.Exec(\"INSERT INTO t1(c1) VALUES (1),(1),(1)\")\n\t\trequire.NoError(t, err)\n\n\t\t// Apply again, should be one successful and one failed migration.\n\t\t_, err = c.MigrateApplySlice(ctx, &atlasexec.MigrateApplyParams{\n\t\t\tEnv: \"local\",\n\t\t})\n\t\trequire.ErrorContains(t, err, \"UNIQUE constraint failed\", \"Should be error\")\n\t\tmae, ok := err.(*atlasexec.MigrateApplyError)\n\t\trequire.True(t, ok, \"Should be a MigrateApplyError\")\n\t\trequire.Len(t, mae.Result, 2, \"Should be two reports\")\n\t\trequire.Equal(t, 1, len(mae.Result[0].Applied), \"Should be one migration applied\")\n\t\trequire.Equal(t, \"20240116003831\", mae.Result[0].Applied[0].Version, \"Should be the correct migration applied\")\n\n\t\trequire.Equal(t, 1, len(mae.Result[1].Applied), \"Should be one migration applied\")\n\t\trequire.Contains(t, mae.Result[1].Error, \"UNIQUE constraint failed\", \"Should be the correct error\")\n\n\t\t// Apply again, should be one successful and one failed migration.\n\t\t_, err = c.MigrateApplySlice(ctx, &atlasexec.MigrateApplyParams{\n\t\t\tEnv: \"local\",\n\t\t})\n\t\trequire.ErrorContains(t, err, \"UNIQUE constraint failed\", \"Should be error\")\n\t\tmae, ok = err.(*atlasexec.MigrateApplyError)\n\t\trequire.True(t, ok, \"Should be a MigrateApplyError\")\n\t\trequire.Len(t, mae.Result, 2, \"Should be two reports\")\n\n\t\trequire.Equal(t, 0, len(mae.Result[0].Applied), \"Should be no migrations applied\")\n\t\trequire.Equal(t, 1, len(mae.Result[1].Applied), \"Should be one tried to apply\")\n\t\trequire.Contains(t, mae.Result[1].Error, \"UNIQUE constraint failed\", \"Should be the correct error\")\n\t})\n}\n\nfunc Test_SchemaPlan(t *testing.T) {\n\trunTestWithVersions(t, []string{\"latest\"}, \"schema-plan\", func(t *testing.T, _ *atlasexec.Version, _ *atlasexec.WorkingDir, c *atlasexec.Client) {\n\t\tctx := context.Background()\n\t\tplan, err := c.SchemaPlan(ctx, &atlasexec.SchemaPlanParams{\n\t\t\tFrom:   []string{\"file://schema-1.lt.hcl\"},\n\t\t\tTo:     []string{\"file://schema-2.lt.hcl\"},\n\t\t\tDevURL: \"sqlite://:memory:?_fk=1\",\n\t\t\tDryRun: true,\n\t\t})\n\t\trequire.NoError(t, err)\n\t\tf := plan.File\n\t\trequire.NotNil(t, f, \"Should have a file\")\n\t\trequire.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\")\n\t\trequire.Empty(t, f.URL, \"Should be no URL\")\n\t})\n\trunTestWithVersions(t, []string{\"latest\"}, \"schema-plan\", func(t *testing.T, _ *atlasexec.Version, _ *atlasexec.WorkingDir, c *atlasexec.Client) {\n\t\tctx := context.Background()\n\t\tplan, err := c.SchemaPlan(ctx, &atlasexec.SchemaPlanParams{\n\t\t\tFrom:   []string{\"file://schema-1.lt.hcl\"},\n\t\t\tTo:     []string{\"file://schema-2.lt.hcl\"},\n\t\t\tDevURL: \"sqlite://:memory:?_fk=1\",\n\t\t\tSave:   true,\n\t\t})\n\t\trequire.NoError(t, err)\n\t\tf := plan.File\n\t\trequire.NotNil(t, f, \"Should have a file\")\n\t\trequire.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\")\n\t\trequire.Regexp(t, \"^file://\\\\d{14}\\\\.plan\\\\.hcl$\", f.URL, \"Should be an URL to a file\")\n\t})\n}\n"
  },
  {
    "path": "atlasexec/internal/e2e/testdata/multi-tenants/atlas.hcl",
    "content": "env {\n  for_each = toset([\n    \"sqlite://bar.db?_fk=1\",\n    \"sqlite://foo.db?_fk=1\",\n  ])\n  name     = atlas.env\n  url      = each.value\n  migration {\n    dir = \"file://migrations\"\n  }\n}\n\n"
  },
  {
    "path": "atlasexec/internal/e2e/testdata/multi-tenants/migrations/20240112070806.sql",
    "content": "CREATE TABLE t1(c1 int);\n"
  },
  {
    "path": "atlasexec/internal/e2e/testdata/multi-tenants/migrations/20240116003831.sql",
    "content": "CREATE UNIQUE INDEX c1_unique ON t1(c1);\n"
  },
  {
    "path": "atlasexec/internal/e2e/testdata/multi-tenants/migrations/atlas.sum",
    "content": "h1:S0UEXIKYA1mHhjFJbnzZh7bzeb42+5KM4HLzVlGuE4Q=\n20240112070806.sql h1:nhoPxDs1H3UH6aEpy1qJ6Bj6zbFRt61sB4ndi0sx7zw=\n20240116003831.sql h1:X3xnvEuBDK23s+re/ZYMdx/Ian+WhvzLgeJBN/2TJrA=\n"
  },
  {
    "path": "atlasexec/internal/e2e/testdata/schema-plan/schema-1.lt.hcl",
    "content": "schema \"public\" {\n  comment = \"This is a test schema\"\n}\n\ntable \"t1\" {\n  schema = schema.public\n  column \"c1\" {\n    type = bigint\n  }\n}\n"
  },
  {
    "path": "atlasexec/internal/e2e/testdata/schema-plan/schema-2.lt.hcl",
    "content": "schema \"public\" {\n  comment = \"This is a test schema\"\n}\n\ntable \"t1\" {\n  schema = schema.public\n  column \"c1\" {\n    type = bigint\n  }\n  column \"c2\" {\n    type = text\n  }\n}\n"
  },
  {
    "path": "atlasexec/internal/e2e/testdata/versioned-basic/atlas.hcl",
    "content": "env \"local\" {\n  migration {\n    dir = \"file://migrations\"\n  }\n}\n"
  },
  {
    "path": "atlasexec/internal/e2e/testdata/versioned-basic/migrations/20240112070806.sql",
    "content": "CREATE TABLE t1(c1 int);\n"
  },
  {
    "path": "atlasexec/internal/e2e/testdata/versioned-basic/migrations/atlas.sum",
    "content": "h1:vefBQWShy7/4OI7C1NqFH9y2PtGtOUS5zFQ1492XitE=\n20240112070806.sql h1:nhoPxDs1H3UH6aEpy1qJ6Bj6zbFRt61sB4ndi0sx7zw=\n"
  },
  {
    "path": "atlasexec/internal/e2e/util_e2e.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage e2etest\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/atlasexec\"\n)\n\nconst testFixtureDir = \"testdata\"\n\nfunc runTestWithVersions(t *testing.T, versions []string, fixtureName string, cb func(t *testing.T, ver *atlasexec.Version, wd *atlasexec.WorkingDir, tf *atlasexec.Client)) {\n\tif os.Getenv(\"ATLASEXEC_E2ETEST\") == \"\" {\n\t\tt.Skip(\"ATLASEXEC_E2ETEST not set\")\n\t}\n\tt.Helper()\n\talreadyRunVersions := map[string]bool{}\n\tfor _, av := range versions {\n\t\tt.Run(fmt.Sprintf(\"%s-%s\", fixtureName, av), func(t *testing.T) {\n\t\t\tif alreadyRunVersions[av] {\n\t\t\t\tt.Skipf(\"already run version %q\", av)\n\t\t\t}\n\t\t\talreadyRunVersions[av] = true\n\n\t\t\tvar execPath string\n\t\t\tif localBinPath := os.Getenv(\"ATLASEXEC_E2ETEST_ATLAS_PATH\"); localBinPath != \"\" {\n\t\t\t\texecPath = localBinPath\n\t\t\t} else {\n\t\t\t\texecPath = downloadAtlas(t, av)\n\t\t\t\tif err := os.Chmod(execPath, 0755); err != nil {\n\t\t\t\t\tt.Fatalf(\"unable to make atlas executable: %s\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t\tc, err := atlasexec.NewClient(\"\", execPath)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t\t// TODO: Check that the version is the same as the one we expect.\n\t\t\trunningVersion, err := c.Version(context.Background())\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"unable to determine running version (expected %q): %s\", av, err)\n\t\t\t}\n\t\t\twd, err := atlasexec.NewWorkingDir()\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t\tdefer wd.Close()\n\t\t\tif fixtureName != \"\" {\n\t\t\t\terr := wd.CopyFS(\"\", os.DirFS(filepath.Join(testFixtureDir, fixtureName)))\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatalf(\"error copying config file into test dir: %s\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t\terr = c.WithWorkDir(wd.Path(), func(c *atlasexec.Client) (err error) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\tvar ok bool\n\t\t\t\t\t\tif err, ok = r.(error); !ok {\n\t\t\t\t\t\t\terr = fmt.Errorf(\"run test failure: %v\", r)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tcb(t, runningVersion, wd, c)\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc downloadAtlas(t *testing.T, version string) string {\n\tt.Helper()\n\tc := http.DefaultClient\n\treq, err := http.NewRequest(http.MethodGet, \"https://atlasgo.sh?test=1\", nil)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\treq.Header.Set(\"User-Agent\", \"AtlasExec/Integration-Test\")\n\tres, err := c.Do(req)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer res.Body.Close()\n\tif res.StatusCode != http.StatusOK {\n\t\tt.Fatalf(\"unexpected status code: %d\", res.StatusCode)\n\t}\n\tpath := filepath.Join(t.TempDir(), \"installer.sh\")\n\tf, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif _, err = io.Copy(f, res.Body); err != nil {\n\t\tf.Close()\n\t\tt.Fatal(err)\n\t} else if err = f.Close(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tatlasBin := filepath.Join(t.TempDir(), \"atlas\")\n\tcmd := exec.Command(path,\n\t\t\"--user-agent\", \"AtlasExec/Integration-Test\",\n\t\t\"--output\", atlasBin,\n\t\t\"--no-install\",\n\t)\n\tcmd.Env = append(os.Environ(), fmt.Sprintf(\"ATLAS_VERSION=%s\", version))\n\tif testing.Verbose() {\n\t\tcmd.Stdout = os.Stdout\n\t\tcmd.Stderr = os.Stderr\n\t}\n\tif err = cmd.Run(); err != nil {\n\t\tt.Fatal(err)\n\t}\n\treturn atlasBin\n}\n"
  },
  {
    "path": "atlasexec/mock-atlas.sh",
    "content": "#!/bin/bash\n\n# TEST_BATCH provide the directory contains all\n# outputs for multiple runs. The path should be absolute\n# or related to current working directory.\nif [[ \"$TEST_BATCH\" != \"\" ]]; then\n  COUNTER_FILE=$TEST_BATCH/counter\n  COUNTER=$(cat $COUNTER_FILE 2>/dev/null)\n  COUNTER=$((COUNTER+1))\n  DIR_CUR=\"$TEST_BATCH/$COUNTER\"\n  if [ ! -d \"$DIR_CUR\" ]; then\n    >&2 echo -n \"$DIR_CUR does not exist, quitting...\"\n    exit 1\n  fi\n  # Save counter for the next runs\n  echo -n $COUNTER > $COUNTER_FILE\n  if [ -f \"$DIR_CUR/args\" ]; then\n    TEST_ARGS=$(cat $DIR_CUR/args)\n  fi\n  if [ -f \"$DIR_CUR/stderr\" ]; then\n    TEST_STDERR=$(cat $DIR_CUR/stderr)\n  fi\n  if [ -f \"$DIR_CUR/stdout\" ]; then\n    TEST_STDOUT=$(cat $DIR_CUR/stdout)\n  fi\nfi\n\nif [[ \"$TEST_ARGS\" != \"$@\" ]]; then\n  >&2 echo \"Receive unexpected args: $@\"\n  exit 1\nfi\n\nif [[ \"$TEST_STDOUT\" != \"\" ]]; then\n  printf \"%s\" \"$TEST_STDOUT\"\n  if [[ \"$TEST_STDERR\" == \"\" ]]; then\n    # `migrate down` and `migrate lint` commands print result to stdout\n    # but the error code is set to 1.\n    exit ${TEST_EXIT_CODE:-0} # No stderr\n  fi\n  # In some cases, Atlas will write the error in stderr\n  # when if the command is partially successful.\n  # eg. Run the apply commands with multiple environments.\n  >&2 echo -n $TEST_STDERR\n  exit 1\nfi\n\nTEST_STDERR=\"${TEST_STDERR:-Missing stderr either stdout input for the test}\"\n>&2 echo -n $TEST_STDERR\nexit 1\n"
  },
  {
    "path": "atlasexec/testdata/broken/20231029112426.sql",
    "content": "broken;"
  },
  {
    "path": "atlasexec/testdata/broken/atlas.sum",
    "content": "h1:Enr95HgKxQs2iSsOANpqDUOaHc6eZeQ+ak0ZF2wjmZE=\n20231029112426.sql h1:lHLnIyWaiYac90Ad0I1SOsPxvQng3tGlq++/8RkpJaI=\n"
  },
  {
    "path": "atlasexec/testdata/migrations/20230727105553_init.sql",
    "content": "CREATE TABLE t1 ( c1 int );\n"
  },
  {
    "path": "atlasexec/testdata/migrations/20230727105615_t2.sql",
    "content": "CREATE TABLE t2 ( c1 int, c2 text );\n"
  },
  {
    "path": "atlasexec/testdata/migrations/20230926085734_destructive-change.sql",
    "content": "DROP TABLE t2;\n"
  },
  {
    "path": "atlasexec/testdata/migrations/atlas.sum",
    "content": "h1:hnQZfRcN6sV+y+0YePtkLazMy+Ty3lhyGv69ixeYoXc=\n20230727105553_init.sql h1:jxgvnWO6tZD3lSPpH1ao5E/6VjapP7iwvBCUJ6aez58=\n20230727105615_t2.sql h1:UvzeoFxe90Y/7b21ziwg6pPzWJQSV7LeYwJl8J63lMU=\n20230926085734_destructive-change.sql h1:Gf/bSvUkfqHr/MEXKCxdGu2YvG8zwe4ER5TW8T/laA0=\n"
  },
  {
    "path": "atlasexec/working_dir.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n)\n\ntype (\n\t// WorkingDir is a temporary directory with a copy of the files from dir.\n\t// It can be used to run commands in the temporary directory.\n\t// The temporary directory is removed when Close is called.\n\tWorkingDir struct {\n\t\tdir string\n\t}\n\t// Option is a function that modifies a ContextExecer.\n\tOption func(ce *WorkingDir) error\n)\n\n// WithAtlasHCLString creates the atlas.hcl file with the given string.\nfunc WithAtlasHCLString(s string) Option {\n\treturn WithAtlasHCL(func(w io.Writer) error {\n\t\t_, err := w.Write([]byte(s))\n\t\treturn err\n\t})\n}\n\n// WithAtlasHCLPath creates the atlas.hcl file by copying the file at the given path.\nfunc WithAtlasHCLPath(path string) Option {\n\treturn WithAtlasHCL(func(w io.Writer) error {\n\t\tf, err := os.Open(path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer f.Close()\n\t\t_, err = io.Copy(w, f)\n\t\treturn err\n\t})\n}\n\n// WithAtlasHCL accept a function to create the atlas.hcl file.\nfunc WithAtlasHCL(fn func(w io.Writer) error) Option {\n\treturn func(ce *WorkingDir) error {\n\t\treturn ce.CreateFile(\"atlas.hcl\", fn)\n\t}\n}\n\n// WithMigrations copies all files from dir to the migrations directory.\n// If dir is nil, no files are copied.\nfunc WithMigrations(dir fs.FS) Option {\n\treturn func(ce *WorkingDir) error {\n\t\tif dir == nil {\n\t\t\treturn nil\n\t\t}\n\t\treturn ce.CopyFS(\"migrations\", dir)\n\t}\n}\n\n// NewWorkingDir creates a new ContextExecer.\n// It creates a temporary directory and copies all files from dir to the temporary directory.\n// The atlasHCL function is called with a writer to create the atlas.hcl file.\n// If atlasHCL is nil, no atlas.hcl file is created.\nfunc NewWorkingDir(opts ...Option) (*WorkingDir, error) {\n\ttmpDir, err := os.MkdirTemp(\"\", \"atlasexec-*\")\n\tif err != nil {\n\t\tif err2 := os.RemoveAll(tmpDir); err2 != nil {\n\t\t\terr = errors.Join(err, err2)\n\t\t}\n\t\treturn nil, err\n\t}\n\tc := &WorkingDir{dir: tmpDir}\n\tfor _, opt := range opts {\n\t\tif err := opt(c); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c, nil\n}\n\n// Close removes the temporary directory.\nfunc (ce *WorkingDir) Close() error {\n\treturn os.RemoveAll(ce.dir)\n}\n\n// DirFS returns a fs.FS for the temporary directory.\nfunc (ce *WorkingDir) DirFS() fs.FS {\n\treturn os.DirFS(ce.dir)\n}\n\n// Dir returns the path to the temporary directory.\nfunc (ce *WorkingDir) Path(elem ...string) string {\n\tif len(elem) == 0 {\n\t\treturn ce.dir\n\t}\n\treturn filepath.Join(append([]string{ce.dir}, elem...)...)\n}\n\n// RunCommand runs the command in the temporary directory.\nfunc (ce *WorkingDir) RunCommand(cmd *exec.Cmd) error {\n\t// Restore the current directory after the command is run.\n\tdefer func(d string) { cmd.Dir = d }(cmd.Dir)\n\tcmd.Dir = ce.dir\n\treturn cmd.Run()\n}\n\n// WriteFile writes the file to the temporary directory.\nfunc (ce *WorkingDir) WriteFile(name string, data []byte) (string, error) {\n\terr := ce.CreateFile(name, func(w io.Writer) (err error) {\n\t\t_, err = w.Write(data)\n\t\treturn err\n\t})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn ce.Path(name), err\n}\n\n// CreateFile creates the file in the temporary directory.\nfunc (ce *WorkingDir) CreateFile(name string, fn func(w io.Writer) error) error {\n\tf, err := os.Create(ce.Path(name))\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := fn(f); err != nil {\n\t\tif err2 := f.Close(); err2 != nil {\n\t\t\terr = errors.Join(err, err2)\n\t\t}\n\t\treturn err\n\t}\n\treturn f.Close()\n}\n\n// CopyFS copies all files from source FileSystem to the destination directory\n// in the temporary directory.\n// If source is nil, an error is returned.\nfunc (ce *WorkingDir) CopyFS(name string, src fs.FS) error {\n\tdst := ce.Path(name)\n\t// Ensure destination directory exists.\n\tif err := os.MkdirAll(dst, 0700); err != nil {\n\t\treturn err\n\t}\n\tswitch dir := src.(type) {\n\tcase nil:\n\t\treturn errors.New(\"atlasexec: source is nil\")\n\tcase migrate.Dir:\n\t\t// The migrate.MemDir doesn't 100% compatible with fs.FS.\n\t\t// It returns fs.ErrNotExist error when open \".\" directory.\n\t\t// So, we need to handle it separately using the Files method.\n\t\tfiles, err := dir.Files()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, f := range files {\n\t\t\tname := filepath.Join(dst, f.Name())\n\t\t\tif err := os.WriteFile(name, f.Bytes(), 0644); err != nil { //nolint:gosec\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\t// If the atlas.sum file exists, copy it to the destination directory.\n\t\tif hf, err := dir.Open(migrate.HashFileName); err == nil {\n\t\t\tdata, err := io.ReadAll(hf)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tname := filepath.Join(dst, migrate.HashFileName)\n\t\t\tif err := os.WriteFile(name, data, 0644); err != nil { //nolint:gosec\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\tdefault:\n\t\treturn fs.WalkDir(dir, \".\", func(path string, d fs.DirEntry, err error) error {\n\t\t\tif err != nil || path == \".\" {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tname := filepath.Join(dst, path)\n\t\t\tif d.IsDir() {\n\t\t\t\treturn os.Mkdir(name, 0700)\n\t\t\t}\n\t\t\tdata, err := fs.ReadFile(dir, path)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn os.WriteFile(name, data, 0644) //nolint:gosec\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "atlasexec/working_dir_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage atlasexec\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"testing/fstest\"\n\t\"text/template\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestContextExecer(t *testing.T) {\n\tsrc := fstest.MapFS{\n\t\t\"bar\": &fstest.MapFile{Data: []byte(\"bar-content\")},\n\t}\n\tce, err := NewWorkingDir()\n\tcheckFileContent := func(t *testing.T, name, expected string) {\n\t\tt.Helper()\n\t\tfull := filepath.Join(ce.dir, name)\n\t\trequire.FileExists(t, full, \"The file %q should exist\", name)\n\t\tactual, err := os.ReadFile(full)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expected, string(actual), \"The file %q should have the expected content\", name)\n\t}\n\trequire.NoError(t, err)\n\trequire.DirExists(t, ce.dir, \"The temporary directory should exist\")\n\trequire.NoFileExists(t, filepath.Join(ce.dir, \"atlas.hcl\"), \"The file atlas.hcl should not exist\")\n\trequire.NoError(t, ce.Close())\n\n\t// Test WithMigrations.\n\tce, err = NewWorkingDir(WithMigrations(src))\n\trequire.NoError(t, err)\n\tcheckFileContent(t, filepath.Join(\"migrations\", \"bar\"), \"bar-content\")\n\trequire.NoError(t, ce.Close())\n\n\t// Test WithMigrations - MemDir.\n\tdir := &migrate.MemDir{}\n\trequire.NoError(t, dir.WriteFile(\"1.sql\", []byte(\"-- only .sql files are copied\\nmem-content\")))\n\trequire.NoError(t, dir.WriteFile(migrate.HashFileName, []byte(\"-- And the atlas.sum\")))\n\tce, err = NewWorkingDir(WithMigrations(dir))\n\trequire.NoError(t, err)\n\tcheckFileContent(t, filepath.Join(\"migrations\", \"1.sql\"), \"-- only .sql files are copied\\nmem-content\")\n\tcheckFileContent(t, filepath.Join(\"migrations\", migrate.HashFileName), \"-- And the atlas.sum\")\n\trequire.NoError(t, ce.Close())\n\n\t// Test WithAtlasHCL.\n\tce, err = NewWorkingDir(\n\t\tWithAtlasHCL(func(w io.Writer) error {\n\t\t\treturn template.Must(template.New(\"\").Parse(`{{ .foo }} & {{ .bar }}`)).\n\t\t\t\tExecute(w, map[string]any{\n\t\t\t\t\t\"foo\": \"foo\",\n\t\t\t\t\t\"bar\": \"bar\",\n\t\t\t\t})\n\t\t}),\n\t\tWithMigrations(src),\n\t)\n\trequire.NoError(t, err)\n\trequire.DirExists(t, ce.dir, \"tmpDir\")\n\tcheckFileContent(t, filepath.Join(\"migrations\", \"bar\"), \"bar-content\")\n\tcheckFileContent(t, \"atlas.hcl\", \"foo & bar\")\n\n\t// Test WriteFile.\n\t_, err = ce.WriteFile(filepath.Join(\"migrations\", \"foo\"), []byte(\"foo-content\"))\n\trequire.NoError(t, err)\n\tcheckFileContent(t, filepath.Join(\"migrations\", \"foo\"), \"foo-content\")\n\n\t// Test RunCommand.\n\tbuf := &bytes.Buffer{}\n\tcmd := exec.Command(\"ls\")\n\tcmd.Dir = \"fake-dir\"\n\tcmd.Stdout = buf\n\trequire.NoError(t, ce.RunCommand(cmd))\n\trequire.Equal(t, \"fake-dir\", cmd.Dir)\n\trequire.Equal(t, \"atlas.hcl\\nmigrations\\n\", buf.String())\n\trequire.NoError(t, ce.Close())\n}\n\nfunc TestMaintainOriginalWorkingDir(t *testing.T) {\n\tdir := t.TempDir()\n\tc, err := NewClient(dir, \"atlas\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, dir, c.workingDir)\n\trequire.NoError(t, c.WithWorkDir(\"bar\", func(c *Client) error {\n\t\trequire.Equal(t, \"bar\", c.workingDir)\n\t\treturn nil\n\t}))\n\trequire.Equal(t, dir, c.workingDir, \"The working directory should not be changed\")\n}\n"
  },
  {
    "path": "cmd/atlas/go.mod",
    "content": "module ariga.io/atlas/cmd/atlas\n\ngo 1.24.13\n\nreplace ariga.io/atlas => ../..\n\nrequire (\n\tariga.io/atlas v0.32.1-0.20250325101103-175b25e1c1b9\n\tentgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4\n\tgithub.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1\n\tgithub.com/antlr4-go/antlr/v4 v4.13.0\n\tgithub.com/aws/aws-sdk-go-v2/config v1.29.17\n\tgithub.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16\n\tgithub.com/chzyer/readline v1.5.1\n\tgithub.com/fatih/color v1.16.0\n\tgithub.com/go-sql-driver/mysql v1.9.3\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/hashicorp/go-retryablehttp v0.7.7\n\tgithub.com/hashicorp/hcl/v2 v2.18.1\n\tgithub.com/lib/pq v1.10.9\n\tgithub.com/mattn/go-isatty v0.0.20\n\tgithub.com/mattn/go-sqlite3 v1.14.28\n\tgithub.com/mitchellh/go-homedir v1.1.0\n\tgithub.com/spf13/cobra v1.8.0\n\tgithub.com/spf13/pflag v1.0.5\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d\n\tgithub.com/vektah/gqlparser/v2 v2.5.16\n\tgithub.com/zclconf/go-cty v1.14.4\n\tgocloud.dev v0.43.0\n\tgolang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8\n\tgolang.org/x/mod v0.26.0\n\tgolang.org/x/oauth2 v0.30.0\n\tgoogle.golang.org/api v0.242.0\n)\n\nrequire (\n\tcloud.google.com/go/auth v0.16.3 // indirect\n\tcloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect\n\tcloud.google.com/go/compute/metadata v0.7.0 // indirect\n\tcloud.google.com/go/iam v1.5.2 // indirect\n\tcloud.google.com/go/longrunning v0.6.7 // indirect\n\tcloud.google.com/go/secretmanager v1.15.0 // indirect\n\tfilippo.io/edwards25519 v1.1.0 // indirect\n\tgithub.com/agext/levenshtein v1.2.3 // indirect\n\tgithub.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect\n\tgithub.com/aws/aws-sdk-go v1.55.7 // indirect\n\tgithub.com/aws/aws-sdk-go-v2 v1.36.5 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect\n\tgithub.com/aws/smithy-go v1.22.4 // indirect\n\tgithub.com/bmatcuk/doublestar v1.3.4 // indirect\n\tgithub.com/coder/websocket v1.8.12 // indirect\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/felixge/httpsnoop v1.0.4 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-openapi/inflect v0.19.0 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/google/s2a-go v0.1.9 // indirect\n\tgithub.com/google/wire v0.6.0 // indirect\n\tgithub.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect\n\tgithub.com/googleapis/gax-go/v2 v2.15.0 // indirect\n\tgithub.com/hashicorp/go-cleanhttp v0.5.2 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/jmespath/go-jmespath v0.4.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mitchellh/go-wordwrap v1.0.1 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/zclconf/go-cty-yaml v1.1.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect\n\tgo.opentelemetry.io/otel v1.37.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.37.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.37.0 // indirect\n\tgo.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.37.0 // indirect\n\tgolang.org/x/crypto v0.40.0 // indirect\n\tgolang.org/x/net v0.42.0 // indirect\n\tgolang.org/x/sync v0.16.0 // indirect\n\tgolang.org/x/sys v0.34.0 // indirect\n\tgolang.org/x/text v0.28.0 // indirect\n\tgolang.org/x/time v0.12.0 // indirect\n\tgolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect\n\tgoogle.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 // indirect\n\tgoogle.golang.org/grpc v1.73.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.8 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "cmd/atlas/go.sum",
    "content": "cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs=\ncloud.google.com/go v0.121.4/go.mod h1:XEBchUiHFJbz4lKBZwYBDHV/rSyfFktk737TLDU089s=\ncloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc=\ncloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA=\ncloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=\ncloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=\ncloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=\ncloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=\ncloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=\ncloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=\ncloud.google.com/go/kms v1.22.0 h1:dBRIj7+GDeeEvatJeTB19oYZNV0aj6wEqSIT/7gLqtk=\ncloud.google.com/go/kms v1.22.0/go.mod h1:U7mf8Sva5jpOb4bxYZdtw/9zsbIjrklYwPcvMk34AL8=\ncloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=\ncloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=\ncloud.google.com/go/secretmanager v1.15.0 h1:RtkCMgTpaBMbzozcRUGfZe46jb9a3qh5EdEtVRUATF8=\ncloud.google.com/go/secretmanager v1.15.0/go.mod h1:1hQSAhKK7FldiYw//wbR/XPfPc08eQ81oBsnRUHEvUc=\nentgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4 h1:d7UZAvQCnOp1PyiHAWkPCXBEPW3tVjraiK/RZlsW0XY=\nentgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4/go.mod h1:zTzLmWtPvGpmSwtkaayM2cm5m819NdM7z7tYPq3vN0U=\nfilippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=\nfilippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=\ngithub.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1 h1:LejjvYg4tCW5HO7q/1nzPrprh47oUD9OUySQ29pDp5c=\ngithub.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1/go.mod h1:cnC/60IoLiDM0GhdKYJ6oO7AwpZe1IQfPnSKlAURgHw=\ngithub.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=\ngithub.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=\ngithub.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=\ngithub.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=\ngithub.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=\ngithub.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=\ngithub.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=\ngithub.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=\ngithub.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac=\ngithub.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=\ngithub.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=\ngithub.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0=\ngithub.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8=\ngithub.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16 h1:j+YO7Khxpk73ESxUpheUSw91qT42+LqNZiEjul1Dmnk=\ngithub.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16/go.mod h1:laSv+AlZPuT/bpJQ2Xspq/oDKhB/XZLohISGTKU7DOg=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4=\ngithub.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7 h1:d+mnMa4JbJlooSbYQfrJpit/YINaB30JEVgrhtjZneA=\ngithub.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7/go.mod h1:1X1NotbcGHH7PCQJ98PsExSxsJj/VWzz8MfFz43+02M=\ngithub.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 h1:OwMzNDe5VVTXD4kGmeK/FtqAITiV8Mw4TCa8IyNO0as=\ngithub.com/aws/aws-sdk-go-v2/service/ssm v1.60.1/go.mod h1:IyVabkWrs8SNdOEZLyFFcW9bUltV4G6OQS0s6H20PHg=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w=\ngithub.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=\ngithub.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=\ngithub.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=\ngithub.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=\ngithub.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=\ngithub.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=\ngithub.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=\ngithub.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=\ngithub.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=\ngithub.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=\ngithub.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=\ngithub.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=\ngithub.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=\ngithub.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=\ngithub.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=\ngithub.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=\ngithub.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=\ngithub.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/go-replayers/grpcreplay v1.3.0 h1:1Keyy0m1sIpqstQmgz307zhiJ1pV4uIlFds5weTmxbo=\ngithub.com/google/go-replayers/grpcreplay v1.3.0/go.mod h1:v6NgKtkijC0d3e3RW8il6Sy5sqRVUwoQa4mHOGEy8DI=\ngithub.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk=\ngithub.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg=\ngithub.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=\ngithub.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=\ngithub.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=\ngithub.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=\ngithub.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=\ngithub.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=\ngithub.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=\ngithub.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=\ngithub.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=\ngithub.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=\ngithub.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=\ngithub.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=\ngithub.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=\ngithub.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=\ngithub.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=\ngithub.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=\ngithub.com/hashicorp/hcl/v2 v2.18.1 h1:6nxnOJFku1EuSawSD81fuviYUV8DxFr3fp2dUi3ZYSo=\ngithub.com/hashicorp/hcl/v2 v2.18.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=\ngithub.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=\ngithub.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=\ngithub.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=\ngithub.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=\ngithub.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=\ngithub.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=\ngithub.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=\ngithub.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=\ngithub.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU=\ngithub.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s=\ngithub.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8=\ngithub.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngithub.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=\ngithub.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=\ngithub.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0=\ngithub.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 h1:rbRJ8BBoVMsQShESYZ0FkvcITu8X8QNwJogcLUmDNNw=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=\ngo.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=\ngo.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=\ngo.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=\ngo.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=\ngo.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=\ngo.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=\ngo.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=\ngo.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=\ngo.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=\ngo.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngocloud.dev v0.43.0 h1:aW3eq4RMyehbJ54PMsh4hsp7iX8cO/98ZRzJJOzN/5M=\ngocloud.dev v0.43.0/go.mod h1:eD8rkg7LhKUHrzkEdLTZ+Ty/vgPHPCd+yMQdfelQVu4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=\ngolang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=\ngolang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=\ngolang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=\ngolang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=\ngolang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=\ngolang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=\ngolang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=\ngolang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=\ngolang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=\ngolang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=\ngolang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=\ngolang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=\ngolang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=\ngolang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=\ngolang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=\ngolang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=\ngolang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=\ngolang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=\ngolang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=\ngolang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=\ngolang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=\ngolang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=\ngolang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=\ngolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=\ngoogle.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg=\ngoogle.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=\ngoogle.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 h1:Nt6z9UHqSlIdIGJdz6KhTIs2VRx/iOsA5iE8bmQNcxs=\ngoogle.golang.org/genproto v0.0.0-20250715232539-7130f93afb79/go.mod h1:kTmlBHMPqR5uCZPBvwa2B18mvubkjyY3CRLI0c6fj0s=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 h1:iOye66xuaAK0WnkPuhQPUFy8eJcmwUXqGGP3om6IxX8=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79/go.mod h1:HKJDgKsFUnv5VAGeQjz8kxcgDP0HoE0iZNp0OdZNlhE=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 h1:1ZwqphdOdWYXsUHgMpU/101nCtf/kSp9hOrcvFsnl10=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=\ngoogle.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=\ngoogle.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=\ngoogle.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=\ngoogle.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "cmd/atlas/internal/cloudapi/client.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cloudapi\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/hashicorp/go-retryablehttp\"\n\t\"github.com/vektah/gqlparser/v2/gqlerror\"\n)\n\nconst (\n\t// defaultURL for Atlas Cloud.\n\tdefaultURL = \"https://api.atlasgo.cloud/query\"\n\t// DefaultProjectName is the default name for projects.\n\tDefaultProjectName = \"default\"\n\t// DefaultDirName is the default directory for reporting\n\t// if no directory was specified by the user.\n\tDefaultDirName = \".atlas\"\n)\n\n// Client is a client for the Atlas Cloud API.\ntype Client struct {\n\tclient   *retryablehttp.Client\n\tendpoint string\n}\n\n// New creates a new Client for the Atlas Cloud API.\nfunc New(endpoint, token string) *Client {\n\tif endpoint == \"\" {\n\t\tendpoint = defaultURL\n\t}\n\tvar (\n\t\tclient    = retryablehttp.NewClient()\n\t\ttransport = client.HTTPClient.Transport\n\t)\n\tclient.HTTPClient.Timeout = time.Second * 30\n\tclient.ErrorHandler = func(res *http.Response, err error, _ int) (*http.Response, error) {\n\t\treturn res, err // Let Client.post handle the error.\n\t}\n\tclient.HTTPClient.Transport = &roundTripper{\n\t\ttoken:        token,\n\t\tbase:         transport,\n\t\textraHeaders: make(map[string]string),\n\t}\n\t// Disable logging until \"ATLAS_DEBUG\" option will be added.\n\tclient.Logger = nil\n\t// Keep retry short for unit/integration tests.\n\tif testing.Testing() || testingURL(endpoint) {\n\t\tclient.HTTPClient.Timeout = 0\n\t\tclient.RetryWaitMin, client.RetryWaitMax = 0, time.Microsecond\n\t}\n\treturn &Client{\n\t\tendpoint: endpoint,\n\t\tclient:   client,\n\t}\n}\n\ntype clientCtxKey struct{}\n\n// NewContext returns a new context with the given Client attached.\nfunc NewContext(parent context.Context, c *Client) context.Context {\n\treturn context.WithValue(parent, clientCtxKey{}, c)\n}\n\n// FromContext returns a Client stored inside a context, or nil if there isn't one.\nfunc FromContext(ctx context.Context) *Client {\n\tc, _ := ctx.Value(clientCtxKey{}).(*Client)\n\treturn c\n}\n\n// DirInput is the input type for retrieving a single directory.\ntype DirInput struct {\n\tSlug string `json:\"slug,omitempty\"`\n\tName string `json:\"name,omitempty\"`\n\tTag  string `json:\"tag,omitempty\"`\n}\n\n// Dir retrieves a directory from the Atlas Cloud API.\nfunc (c *Client) Dir(ctx context.Context, input DirInput) (migrate.Dir, error) {\n\tvar (\n\t\tpayload struct {\n\t\t\tDir struct {\n\t\t\t\tContent []byte `json:\"content\"`\n\t\t\t} `json:\"dirState\"`\n\t\t}\n\t\tquery = `\n\t\tquery dirState($input: DirStateInput!) {\n\t\t   dirState(input: $input) {\n\t\t     content\n\t\t   }\n\t\t}`\n\t\tvars = struct {\n\t\t\tInput DirInput `json:\"input\"`\n\t\t}{\n\t\t\tInput: input,\n\t\t}\n\t)\n\tif err := c.post(ctx, query, vars, &payload); err != nil {\n\t\treturn nil, err\n\t}\n\treturn migrate.UnarchiveDir(payload.Dir.Content)\n}\n\ntype (\n\t// DeployContextInput is an input type for describing the context in which\n\t// `migrate-apply` was used. For example, a GitHub Action with version v1.2.3\n\tDeployContextInput struct {\n\t\tTriggerType    string `json:\"triggerType,omitempty\"`\n\t\tTriggerVersion string `json:\"triggerVersion,omitempty\"`\n\t}\n\n\t// ReportMigrationSetInput represents the input type for reporting a set of migration deployments.\n\tReportMigrationSetInput struct {\n\t\tID        string                 `json:\"id\"`\n\t\tPlanned   int                    `json:\"planned\"`\n\t\tStartTime time.Time              `json:\"startTime\"`\n\t\tEndTime   time.Time              `json:\"endTime\"`\n\t\tError     *string                `json:\"error,omitempty\"`\n\t\tLog       []ReportStep           `json:\"log,omitempty\"`\n\t\tCompleted []ReportMigrationInput `json:\"completed,omitempty\"`\n\t\tContext   *DeployContextInput    `json:\"context,omitempty\"`\n\t}\n\n\t// ReportMigrationInput represents an input type for reporting a migration deployments.\n\tReportMigrationInput struct {\n\t\tProjectName    string              `json:\"projectName\"`\n\t\tEnvName        string              `json:\"envName\"`\n\t\tDirName        string              `json:\"dirName\"`\n\t\tAtlasVersion   string              `json:\"atlasVersion\"`\n\t\tTarget         DeployedTargetInput `json:\"target\"`\n\t\tStartTime      time.Time           `json:\"startTime\"`\n\t\tEndTime        time.Time           `json:\"endTime\"`\n\t\tFromVersion    string              `json:\"fromVersion\"`\n\t\tToVersion      string              `json:\"toVersion\"`\n\t\tCurrentVersion string              `json:\"currentVersion\"`\n\t\tError          *string             `json:\"error,omitempty\"`\n\t\tFiles          []DeployedFileInput `json:\"files\"`\n\t\tLog            string              `json:\"log\"`\n\t\tContext        *DeployContextInput `json:\"context,omitempty\"`\n\t\tDryRun         bool                `json:\"dryRun,omitempty\"`\n\t}\n\n\t// DeployedTargetInput represents the input type for a deployed target.\n\tDeployedTargetInput struct {\n\t\tID     string `json:\"id\"`\n\t\tSchema string `json:\"schema\"`\n\t\tURL    string `json:\"url\"` // URL string without userinfo.\n\t}\n\n\t// DeployedFileInput represents the input type for a deployed file.\n\tDeployedFileInput struct {\n\t\tName      string            `json:\"name\"`\n\t\tContent   string            `json:\"content\"`\n\t\tStartTime time.Time         `json:\"startTime\"`\n\t\tEndTime   time.Time         `json:\"endTime\"`\n\t\tSkipped   int               `json:\"skipped\"`\n\t\tApplied   int               `json:\"applied\"`\n\t\tChecks    []FileChecksInput `json:\"checks\"`\n\t\tError     *StmtErrorInput   `json:\"error,omitempty\"`\n\t}\n\n\t// FileChecksInput represents the input type for a file checks.\n\tFileChecksInput struct {\n\t\tName   string           `json:\"name\"`\n\t\tStart  time.Time        `json:\"start\"`\n\t\tEnd    time.Time        `json:\"end\"`\n\t\tChecks []CheckStmtInput `json:\"checks\"`\n\t\tError  *StmtErrorInput  `json:\"error,omitempty\"`\n\t}\n\n\t// CheckStmtInput represents the input type for a statement check.\n\tCheckStmtInput struct {\n\t\tStmt  string  `json:\"stmt\"`\n\t\tError *string `json:\"error,omitempty\"`\n\t}\n\n\t// StmtErrorInput represents the input type for a statement error.\n\tStmtErrorInput struct {\n\t\tStmt string `json:\"stmt\"`\n\t\tText string `json:\"text\"`\n\t}\n\n\t// ReportStep is top-level step in a report.\n\tReportStep struct {\n\t\tText      string          `json:\"text\"`\n\t\tStartTime time.Time       `json:\"startTime\"`\n\t\tEndTime   time.Time       `json:\"endTime\"`\n\t\tError     bool            `json:\"error,omitempty\"`\n\t\tLog       []ReportStepLog `json:\"log,omitempty\"`\n\t}\n\t// ReportStepLog is a log entry in a step.\n\tReportStepLog struct {\n\t\tText     string          `json:\"text,omitempty\"`\n\t\tChildren []ReportStepLog `json:\"children,omitempty\"`\n\t}\n)\n\n// ReportMigrationSet reports a set of migration deployments to the Atlas Cloud API.\nfunc (c *Client) ReportMigrationSet(ctx context.Context, input ReportMigrationSetInput) (string, error) {\n\tvar (\n\t\tpayload struct {\n\t\t\tReportMigrationSet struct {\n\t\t\t\tURL string `json:\"url\"`\n\t\t\t} `json:\"reportMigrationSet\"`\n\t\t}\n\t\tquery = `\n\t\tmutation ReportMigrationSet($input: ReportMigrationSetInput!) {\n\t\t   reportMigrationSet(input: $input) {\n\t\t     url\n\t\t   }\n\t\t}`\n\t\tvars = struct {\n\t\t\tInput ReportMigrationSetInput `json:\"input\"`\n\t\t}{\n\t\t\tInput: input,\n\t\t}\n\t)\n\tif err := c.post(ctx, query, vars, &payload); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn payload.ReportMigrationSet.URL, nil\n}\n\n// ReportMigration reports a migration deployment to the Atlas Cloud API.\nfunc (c *Client) ReportMigration(ctx context.Context, input ReportMigrationInput) (string, error) {\n\tvar (\n\t\tpayload struct {\n\t\t\tReportMigration struct {\n\t\t\t\tURL string `json:\"url\"`\n\t\t\t} `json:\"reportMigration\"`\n\t\t}\n\t\tquery = `\n\t\tmutation ReportMigration($input: ReportMigrationInput!) {\n\t\t   reportMigration(input: $input) {\n\t\t     url\n\t\t   }\n\t\t}`\n\t\tvars = struct {\n\t\t\tInput ReportMigrationInput `json:\"input\"`\n\t\t}{\n\t\t\tInput: input,\n\t\t}\n\t)\n\tif err := c.post(ctx, query, vars, &payload); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn payload.ReportMigration.URL, nil\n}\n\n// ErrUnauthorized is returned when the server returns a 401 status code.\nvar ErrUnauthorized = errors.New(http.StatusText(http.StatusUnauthorized))\n\nfunc (c *Client) post(ctx context.Context, query string, vars, data any) error {\n\tbody, err := json.Marshal(struct {\n\t\tQuery     string `json:\"query\"`\n\t\tVariables any    `json:\"variables,omitempty\"`\n\t}{\n\t\tQuery:     query,\n\t\tVariables: vars,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\treq, err := retryablehttp.NewRequestWithContext(ctx, http.MethodPost, c.endpoint, bytes.NewReader(body))\n\tif err != nil {\n\t\treturn err\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tres, err := c.client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer res.Body.Close()\n\tswitch {\n\tcase res.StatusCode == http.StatusUnauthorized:\n\t\treturn ErrUnauthorized\n\tcase res.StatusCode != http.StatusOK:\n\t\tbuf, err := io.ReadAll(io.LimitReader(res.Body, 1<<20))\n\t\tif err != nil {\n\t\t\treturn &HTTPError{StatusCode: res.StatusCode, Message: err.Error()}\n\t\t}\n\t\tvar v struct {\n\t\t\tErrors errlist `json:\"errors,omitempty\"`\n\t\t}\n\t\tif err := json.Unmarshal(buf, &v); err != nil || len(v.Errors) == 0 {\n\t\t\t// If the error is not a GraphQL error, return the message as is.\n\t\t\treturn &HTTPError{StatusCode: res.StatusCode, Message: string(bytes.TrimSpace(buf))}\n\t\t}\n\t\treturn v.Errors\n\t}\n\tvar scan = struct {\n\t\tData   any     `json:\"data\"`\n\t\tErrors errlist `json:\"errors,omitempty\"`\n\t}{\n\t\tData: data,\n\t}\n\tif err := json.NewDecoder(res.Body).Decode(&scan); err != nil && !errors.Is(err, io.EOF) {\n\t\treturn fmt.Errorf(\"decoding response: %w\", err)\n\t}\n\tif len(scan.Errors) > 0 {\n\t\treturn scan.Errors\n\t}\n\treturn nil\n}\n\n// AddHeader adds a header to the client requests.\nfunc (c *Client) AddHeader(key, value string) {\n\trt, ok := c.client.HTTPClient.Transport.(*roundTripper)\n\tif !ok {\n\t\treturn\n\t}\n\trt.extraHeaders[key] = value\n}\n\ntype (\n\t// errlist wraps the gqlerror.List to print errors without\n\t// extra newlines and prefix info added.\n\terrlist gqlerror.List\n\t// roundTripper is a http.RoundTripper that adds the Authorization header.\n\troundTripper struct {\n\t\ttoken        string\n\t\textraHeaders map[string]string\n\t\tbase         http.RoundTripper\n\t}\n)\n\nfunc (e errlist) Error() string {\n\ts := strings.TrimPrefix(gqlerror.List(e).Error(), \"input:\")\n\treturn strings.TrimSpace(s)\n}\n\n// RoundTrip implements http.RoundTripper.\nfunc (r *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {\n\tSetHeader(req, r.token)\n\tfor k, v := range r.extraHeaders {\n\t\treq.Header.Set(k, v)\n\t}\n\treturn r.base.RoundTrip(req)\n}\n\n// HTTPError represents a generic HTTP error. Hence, non 2xx status codes.\ntype HTTPError struct {\n\tStatusCode int\n\tMessage    string\n}\n\nfunc (e *HTTPError) Error() string {\n\treturn fmt.Sprintf(\"unexpected error code %d: %s\", e.StatusCode, e.Message)\n}\n\n// RedactedURL returns a URL string with the userinfo redacted.\nfunc RedactedURL(s string) (string, error) {\n\tu, err := sqlclient.ParseURL(s)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn u.Redacted(), nil\n}\n\n// version of the CLI set by cmdapi.\nvar version = \"development\"\n\n// SetVersion allow cmdapi to set the version\n// of the CLI provided at build time.\nfunc SetVersion(v, flavor string) {\n\tversion = v\n\tif flavor != \"\" {\n\t\tversion += \"-\" + flavor\n\t}\n}\n\n// SetHeader sets header fields for cloud requests.\nfunc SetHeader(req *http.Request, token string) {\n\tfor k, v := range header(token) {\n\t\treq.Header.Set(k, v[0])\n\t}\n}\n\nfunc header(token string) http.Header {\n\th := make(http.Header)\n\th.Set(\"Authorization\", \"Bearer \"+token)\n\th.Set(\"User-Agent\", UserAgent())\n\th.Set(\"Content-Type\", \"application/json\")\n\treturn h\n}\n\n// UserAgent is the value the CLI uses in the User-Agent HTTP header.\nfunc UserAgent(systems ...string) string {\n\tsysInfo := runtime.GOOS + \"/\" + runtime.GOARCH\n\tif len(systems) > 0 {\n\t\tsystems = slices.DeleteFunc(systems, func(s string) bool {\n\t\t\treturn strings.TrimSpace(s) == \"\"\n\t\t})\n\t\tsysInfo = strings.Join(slices.Insert(systems, 0, sysInfo), \"; \")\n\t}\n\treturn fmt.Sprintf(\"Atlas/%s (%s)\", version, sysInfo)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cloudapi/client_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage cloudapi\n\nimport (\n\t\"net/url\"\n)\n\nfunc testingURL(endpoint string) bool {\n\tu, err := url.Parse(endpoint)\n\tif err != nil {\n\t\treturn false\n\t}\n\thost := u.Hostname()\n\treturn host == \"localhost\" || host == \"127.0.0.1\"\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cloudapi/client_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cloudapi\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestClient_Dir(t *testing.T) {\n\tvar dir migrate.MemDir\n\trequire.NoError(t, dir.WriteFile(\"1.sql\", []byte(\"create table foo (id int)\")))\n\tad, err := migrate.ArchiveDir(&dir)\n\trequire.NoError(t, err)\n\tSetVersion(\"v0.13.0\", \"\")\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar input struct {\n\t\t\tVariables struct {\n\t\t\t\tDirInput DirInput `json:\"input\"`\n\t\t\t} `json:\"variables\"`\n\t\t}\n\t\terr := json.NewDecoder(r.Body).Decode(&input)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"foo\", input.Variables.DirInput.Name)\n\t\trequire.Equal(t, \"x\", input.Variables.DirInput.Tag)\n\t\trequire.Equal(t, \"Bearer atlas\", r.Header.Get(\"Authorization\"))\n\t\texpUA := fmt.Sprintf(\"Atlas/v0.13.0 (%s/%s)\", runtime.GOOS, runtime.GOARCH)\n\t\trequire.Equal(t, expUA, r.Header.Get(\"User-Agent\"))\n\t\tfmt.Fprintf(w, `{\"data\":{\"dirState\":{\"content\":%q}}}`, base64.StdEncoding.EncodeToString(ad))\n\t}))\n\tclient := New(srv.URL, \"atlas\")\n\tdefer srv.Close()\n\tgd, err := client.Dir(context.Background(), DirInput{\n\t\tName: \"foo\",\n\t\tTag:  \"x\",\n\t})\n\trequire.NoError(t, err)\n\tgcheck, err := gd.Checksum()\n\trequire.NoError(t, err)\n\tdcheck, err := dir.Checksum()\n\trequire.NoError(t, err)\n\trequire.Equal(t, dcheck.Sum(), gcheck.Sum())\n}\n\nfunc TestClient_GraphQLError(t *testing.T) {\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(http.StatusUnprocessableEntity)\n\t\t_, err := w.Write([]byte(`{\"errors\":[{\"message\":\"error\\n\",\"path\":[\"variable\",\"input\",\"driver\"],\"extensions\":{}}],\"data\":null}`))\n\t\trequire.NoError(t, err)\n\t}))\n\tclient := New(srv.URL, \"atlas\")\n\tdefer srv.Close()\n\tlink, err := client.ReportMigration(context.Background(), ReportMigrationInput{\n\t\tEnvName:     \"foo\",\n\t\tProjectName: \"bar\",\n\t})\n\trequire.EqualError(t, err, \"variable.input.driver error\", \"error is trimmed\")\n\trequire.Empty(t, link)\n}\n\nfunc TestClient_HTTPError(t *testing.T) {\n\tvar (\n\t\tbody string\n\t\tcode = http.StatusInternalServerError\n\t)\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Error(w, body, code)\n\t}))\n\tclient := New(srv.URL, \"atlas\")\n\tdefer srv.Close()\n\tbody = \"internal error\"\n\t_, err := client.ReportMigration(context.Background(), ReportMigrationInput{\n\t\tEnvName:     \"foo\",\n\t\tProjectName: \"bar\",\n\t})\n\trequire.EqualError(t, err, `unexpected error code 500: internal error`)\n\n\t// Error should be limited to 1MB.\n\tbody = fmt.Sprintf(\"%s!\", strings.Repeat(\"a\", 1<<20))\n\t_, err = client.ReportMigration(context.Background(), ReportMigrationInput{\n\t\tEnvName:     \"foo\",\n\t\tProjectName: \"bar\",\n\t})\n\trequire.ErrorContains(t, err, \"unexpected error code 500: a\")\n\trequire.NotContains(t, err.Error(), \"!\")\n\n\t// Unauthorized error.\n\tbody = \"unauthorized\"\n\tcode = http.StatusUnauthorized\n\t_, err = client.ReportMigration(context.Background(), ReportMigrationInput{\n\t\tEnvName:     \"foo\",\n\t\tProjectName: \"bar\",\n\t})\n\trequire.ErrorIs(t, err, ErrUnauthorized)\n\n\tcode = http.StatusForbidden\n\tbody = \"Forbidden\"\n\t_, err = client.ReportMigration(context.Background(), ReportMigrationInput{\n\t\tEnvName:     \"foo\",\n\t\tProjectName: \"bar\",\n\t})\n\trequire.EqualError(t, err, \"unexpected error code 403: Forbidden\")\n\n\tcode = http.StatusConflict\n\tbody = `{\"errors\":[{\"message\":\"conflict\\n\",\"path\":[\"variable\",\"input\",\"driver\"],\"extensions\":{}}],\"data\":null}`\n\t_, err = client.ReportMigration(context.Background(), ReportMigrationInput{\n\t\tEnvName:     \"foo\",\n\t\tProjectName: \"bar\",\n\t})\n\trequire.EqualError(t, err, \"variable.input.driver conflict\", \"GraphQL error\")\n}\n\nfunc TestClient_ReportMigration(t *testing.T) {\n\tconst project, env = \"atlas\", \"dev\"\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar input struct {\n\t\t\tVariables struct {\n\t\t\t\tInput ReportMigrationInput `json:\"input\"`\n\t\t\t} `json:\"variables\"`\n\t\t}\n\t\terr := json.NewDecoder(r.Body).Decode(&input)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, env, input.Variables.Input.EnvName)\n\t\trequire.Equal(t, project, input.Variables.Input.ProjectName)\n\t\tfmt.Fprintf(w, `{\"data\":{\"reportMigration\":{\"url\":\"https://atlas.com\"}}}`)\n\t}))\n\tclient := New(srv.URL, \"atlas\")\n\tdefer srv.Close()\n\tlink, err := client.ReportMigration(context.Background(), ReportMigrationInput{\n\t\tEnvName:     env,\n\t\tProjectName: project,\n\t})\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, link)\n}\n\nfunc TestClient_ReportMigrationSet(t *testing.T) {\n\tconst (\n\t\tplanned               = 2\n\t\tid, log, project, env = \"deployment-set-1\", \"started deployment\", \"atlas\", \"dev\"\n\t)\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tvar input struct {\n\t\t\tVariables struct {\n\t\t\t\tInput ReportMigrationSetInput `json:\"input\"`\n\t\t\t} `json:\"variables\"`\n\t\t}\n\t\terr := json.NewDecoder(r.Body).Decode(&input)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, id, input.Variables.Input.ID)\n\t\trequire.Equal(t, []ReportStep{{Text: log}}, input.Variables.Input.Log)\n\t\trequire.Equal(t, planned, input.Variables.Input.Planned)\n\t\trequire.Equal(t, env, input.Variables.Input.Completed[0].EnvName)\n\t\trequire.Equal(t, project, input.Variables.Input.Completed[0].ProjectName)\n\t\trequire.Equal(t, \"dir-1\", input.Variables.Input.Completed[0].DirName)\n\t\trequire.Equal(t, env, input.Variables.Input.Completed[1].EnvName)\n\t\trequire.Equal(t, project, input.Variables.Input.Completed[1].ProjectName)\n\t\trequire.Equal(t, \"dir-2\", input.Variables.Input.Completed[1].DirName)\n\t\tfmt.Fprintf(w, `{\"data\":{\"reportMigrationSet\":{\"url\":\"https://atlas.com\"}}}`)\n\t}))\n\tclient := New(srv.URL, \"atlas\")\n\tdefer srv.Close()\n\tlink, err := client.ReportMigrationSet(context.Background(), ReportMigrationSetInput{\n\t\tID:      id,\n\t\tPlanned: planned,\n\t\tLog:     []ReportStep{{Text: log}},\n\t\tCompleted: []ReportMigrationInput{\n\t\t\t{\n\t\t\t\tEnvName:     env,\n\t\t\t\tProjectName: project,\n\t\t\t\tDirName:     \"dir-1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tEnvName:     env,\n\t\t\t\tProjectName: project,\n\t\t\t\tDirName:     \"dir-2\",\n\t\t\t},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, link)\n}\n\nfunc TestRedactedURL(t *testing.T) {\n\tu, err := RedactedURL(\"mysql://user:pass@:3306/db\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"mysql://user:xxxxx@:3306/db\", u)\n\tu, err = RedactedURL(\"\\\\n mysql://user:pass@:3306/db\")\n\trequire.EqualError(t, err, `first path segment in URL cannot contain colon`)\n\trequire.Empty(t, u)\n}\n\nfunc TestUserAgent(t *testing.T) {\n\tplatform := runtime.GOOS + \"/\" + runtime.GOARCH\n\trequire.Equal(t, fmt.Sprintf(\"Atlas/%s (%s)\", version, platform), UserAgent())\n\trequire.Equal(t, fmt.Sprintf(\"Atlas/%s (%s; foo/bar; bar/baz)\", version, platform), UserAgent(\"foo/bar\", \"bar/baz\"))\n\trequire.Equal(t, fmt.Sprintf(\"Atlas/%s (%s; bar/baz)\", version, platform), UserAgent(\"  \", \"\", \"bar/baz\"))\n}\n\nfunc TestClient_AddHeader(t *testing.T) {\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\trequire.Equal(t, \"val\", r.Header.Get(\"key\"))\n\t}))\n\tclient := New(srv.URL, \"atlas\")\n\tdefer srv.Close()\n\tclient.AddHeader(\"key\", \"val\")\n\t_, err := client.ReportMigration(context.Background(), ReportMigrationInput{\n\t\tEnvName:     \"foo\",\n\t\tProjectName: \"bar\",\n\t})\n\trequire.NoError(t, err)\n}\n\nfunc TestClient_Retry(t *testing.T) {\n\tvar (\n\t\tcalls = []int{http.StatusInternalServerError, http.StatusInternalServerError, http.StatusOK}\n\t\tsrv   = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\trequire.Equal(t, \"val\", r.Header.Get(\"key\"))\n\t\t\trequire.Equal(t, \"Bearer atlas\", r.Header.Get(\"Authorization\"))\n\t\t\tw.WriteHeader(calls[0])\n\t\t\tcalls = calls[1:]\n\t\t}))\n\t\tclient = New(srv.URL, \"atlas\")\n\t)\n\tdefer srv.Close()\n\tclient.AddHeader(\"key\", \"val\")\n\t_, err := client.ReportMigration(context.Background(), ReportMigrationInput{\n\t\tEnvName: \"foo\",\n\t})\n\trequire.NoError(t, err)\n\trequire.Empty(t, calls)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/cmdapi.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Package cmdapi holds the atlas commands used to build an atlas distribution.\npackage cmdapi\n\nimport (\n\t\"context\"\n\t\"encoding/csv\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdext\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\t\"github.com/zclconf/go-cty/cty\"\n\t\"golang.org/x/exp/maps\"\n\t\"golang.org/x/mod/semver\"\n)\n\nvar (\n\t// Root represents the root command when called without any subcommands.\n\tRoot = &cobra.Command{\n\t\tUse:          \"atlas\",\n\t\tShort:        \"Manage your database schema as code\",\n\t\tSilenceUsage: true,\n\t}\n\n\t// GlobalFlags contains flags common to many Atlas sub-commands.\n\tGlobalFlags struct {\n\t\t// Config defines the path to the Atlas project/config file.\n\t\tConfigURL string\n\t\t// SelectedEnv contains the environment selected from the active project via the --env flag.\n\t\tSelectedEnv string\n\t\t// Vars contains the input variables passed from the CLI to Atlas DDL or project files.\n\t\tVars Vars\n\t}\n\n\t// flavor holds Atlas flavor. Custom flavors (like the community build) should set this by build flag\n\t// \"-X 'ariga.io/atlas/cmd/atlas/internal/cmdapi.flavor=community'\"\n\tflavor string\n\n\t// version holds Atlas version. When built with cloud packages should be set by build flag, e.g.\n\t// \"-X 'ariga.io/atlas/cmd/atlas/internal/cmdapi.version=v0.1.2'\"\n\tversion string\n\n\t// versionCmd represents the subcommand 'atlas version'.\n\tversionCmd = &cobra.Command{\n\t\tUse:   \"version\",\n\t\tShort: \"Prints this Atlas CLI version information.\",\n\t\tRun: func(cmd *cobra.Command, _ []string) {\n\t\t\tvar (\n\t\t\t\tf    = versionFmt\n\t\t\t\targs []any\n\t\t\t)\n\t\t\tif flavor != \"\" {\n\t\t\t\tf += \"%s \"\n\t\t\t\targs = append(args, flavor)\n\t\t\t}\n\t\t\tf += \"version %s\\n%s\\n%s\"\n\t\t\tv, u := parseV(version)\n\t\t\targs = append(args, v, u, versionInfo)\n\t\t\tcmd.Printf(f, args...)\n\t\t},\n\t}\n\n\t// license holds Atlas license. When built with cloud packages should be set by build flag\n\t// \"-X 'ariga.io/atlas/cmd/atlas/internal/cmdapi.license=${license}'\"\n\tlicense = `LICENSE\nAtlas is licensed under Apache 2.0 as found in https://github.com/ariga/atlas/blob/master/LICENSE.`\n\n\t// licenseCmd represents the subcommand 'atlas license'.\n\tlicenseCmd = &cobra.Command{\n\t\tUse:   \"license\",\n\t\tShort: \"Display license information\",\n\t\tRun: func(cmd *cobra.Command, _ []string) {\n\t\t\tcmd.Println(license)\n\t\t},\n\t}\n)\n\ntype (\n\t// ErrorFormatter implemented by the errors below to\n\t// allow them format command output on error.\n\tErrorFormatter interface {\n\t\tFormatError(*cobra.Command)\n\t}\n\t// FormattedError is an error that format the command output when returned.\n\tFormattedError struct {\n\t\tErr    error\n\t\tPrefix string // Prefix to use on error.\n\t\tSilent bool   // Silent errors are not printed.\n\t}\n\t// AbortError returns a command error that is formatted as \"Abort: ...\" when\n\t// the execution is aborted by the user.\n\tAbortError struct {\n\t\tErr error\n\t}\n\t// Aborter allows errors to signal if the error is an abort error.\n\tAborter interface {\n\t\terror\n\t\tIsAbort()\n\t}\n)\n\nfunc (e *FormattedError) Error() string { return e.Err.Error() }\n\nfunc (e *FormattedError) FormatError(cmd *cobra.Command) {\n\tcmd.SilenceErrors = e.Silent\n\tif e.Prefix != \"\" {\n\t\tcmd.SetErrPrefix(e.Prefix)\n\t}\n}\n\n// AbortErrorf is like fmt.Errorf for creating AbortError.\nfunc AbortErrorf(format string, a ...any) error {\n\treturn &AbortError{Err: fmt.Errorf(format, a...)}\n}\n\nfunc (e *AbortError) Error() string { return e.Err.Error() }\n\nfunc (e *AbortError) FormatError(cmd *cobra.Command) {\n\tcmd.SetErrPrefix(\"Abort:\")\n}\n\nfunc (e *AbortError) Unwrap() error {\n\treturn e.Err\n}\n\n// RunE wraps the command cobra.Command.RunE function with additional postrun logic.\nfunc RunE(f func(*cobra.Command, []string) error) func(*cobra.Command, []string) error {\n\treturn func(cmd *cobra.Command, args []string) (err error) {\n\t\tif err = f(cmd, args); err != nil {\n\t\t\tif err1 := (Aborter)(nil); errors.As(err, &err1) {\n\t\t\t\terr = &AbortError{Err: err}\n\t\t\t}\n\t\t\tif ef, ok := err.(ErrorFormatter); ok {\n\t\t\t\tef.FormatError(cmd)\n\t\t\t}\n\t\t}\n\t\treturn err\n\t}\n}\n\nfunc init() {\n\tRoot.AddCommand(versionCmd)\n\tRoot.AddCommand(licenseCmd)\n\t// Register a global function to clean up the global\n\t// flags regardless if the command passed or failed.\n\tcobra.OnFinalize(func() {\n\t\tGlobalFlags.ConfigURL = \"\"\n\t\tGlobalFlags.Vars = nil\n\t\tGlobalFlags.SelectedEnv = \"\"\n\t})\n}\n\n// parseV returns a user facing version and release notes url\nfunc parseV(version string) (string, string) {\n\tu := \"https://github.com/ariga/atlas/releases/latest\"\n\tif ok := semver.IsValid(version); !ok {\n\t\treturn \"- development\", u\n\t}\n\ts := strings.Split(version, \"-\")\n\tif len(s) != 0 && s[len(s)-1] != \"canary\" {\n\t\tu = fmt.Sprintf(\"https://github.com/ariga/atlas/releases/tag/%s\", version)\n\t}\n\treturn version, u\n}\n\n// Version returns the current Atlas binary version.\nfunc Version() string {\n\treturn version\n}\n\n// Vars implements pflag.Value.\ntype Vars map[string]cty.Value\n\n// String implements pflag.Value.String.\nfunc (v Vars) String() string {\n\tvar (\n\t\tb  strings.Builder\n\t\tks = maps.Keys(v)\n\t)\n\tsort.Strings(ks)\n\tfor _, k := range ks {\n\t\tif b.Len() > 0 {\n\t\t\tb.WriteString(\", \")\n\t\t}\n\t\tb.WriteString(k)\n\t\tb.WriteString(\":\")\n\t\tswitch v1 := v[k]; v1.Type() {\n\t\tcase cty.String:\n\t\t\tb.WriteString(v1.AsString())\n\t\tcase cty.List(cty.String):\n\t\t\tb.WriteString(\"[\")\n\t\t\tfor i, v2 := range v1.AsValueSlice() {\n\t\t\t\tif i > 0 {\n\t\t\t\t\tb.WriteString(\", \")\n\t\t\t\t}\n\t\t\t\tb.WriteString(v2.AsString())\n\t\t\t}\n\t\t\tb.WriteString(\"]\")\n\t\tdefault:\n\t\t\tb.WriteString(v1.GoString())\n\t\t}\n\t}\n\treturn \"[\" + b.String() + \"]\"\n}\n\n// Copy returns a copy of the current variables.\nfunc (v Vars) Copy() Vars {\n\tvc := make(Vars)\n\tfor k := range v {\n\t\tvc[k] = v[k]\n\t}\n\treturn vc\n}\n\n// Replace overrides the variables.\nfunc (v *Vars) Replace(vc Vars) {\n\t*v = vc\n}\n\n// Set implements pflag.Value.Set.\nfunc (v *Vars) Set(s string) error {\n\tif *v == nil {\n\t\t*v = make(Vars)\n\t}\n\tkvs, err := csv.NewReader(strings.NewReader(s)).Read()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor i := range kvs {\n\t\tkv := strings.SplitN(kvs[i], \"=\", 2)\n\t\tif len(kv) != 2 {\n\t\t\treturn fmt.Errorf(\"variables must be format as key=value, got: %q\", kvs[i])\n\t\t}\n\t\tv1 := cty.StringVal(kv[1])\n\t\tswitch v0, ok := (*v)[kv[0]]; {\n\t\tcase ok && v0.Type().IsListType():\n\t\t\t(*v)[kv[0]] = cty.ListVal(append(v0.AsValueSlice(), v1))\n\t\tcase ok:\n\t\t\t(*v)[kv[0]] = cty.ListVal([]cty.Value{v0, v1})\n\t\tdefault:\n\t\t\t(*v)[kv[0]] = v1\n\t\t}\n\t}\n\treturn nil\n}\n\n// Type implements pflag.Value.Type.\nfunc (v *Vars) Type() string {\n\treturn \"<name>=<value>\"\n}\n\nconst (\n\tflagAllowDirty     = \"allow-dirty\"\n\tflagEdit           = \"edit\"\n\tflagAutoApprove    = \"auto-approve\"\n\tflagBaseline       = \"baseline\"\n\tflagConfig         = \"config\"\n\tflagContext        = \"context\"\n\tflagDevURL         = \"dev-url\"\n\tflagDirURL         = \"dir\"\n\tflagDirFormat      = \"dir-format\"\n\tflagDryRun         = \"dry-run\"\n\tflagEnv            = \"env\"\n\tflagExclude        = \"exclude\"\n\tflagInclude        = \"include\"\n\tflagFile           = \"file\"\n\tflagFrom           = \"from\"\n\tflagFromShort      = \"f\"\n\tflagFormat         = \"format\"\n\tflagGitBase        = \"git-base\"\n\tflagGitDir         = \"git-dir\"\n\tflagLatest         = \"latest\"\n\tflagLockTimeout    = \"lock-timeout\"\n\tflagLog            = \"log\"\n\tflagPlan           = \"plan\"\n\tflagRevisionSchema = \"revisions-schema\"\n\tflagSchema         = \"schema\"\n\tflagSchemaShort    = \"s\"\n\tflagTo             = \"to\"\n\tflagTxMode         = \"tx-mode\"\n\tflagExecOrder      = \"exec-order\"\n\tflagURL            = \"url\"\n\tflagURLShort       = \"u\"\n\tflagVar            = \"var\"\n\tflagQualifier      = \"qualifier\"\n)\n\nfunc addGlobalFlags(set *pflag.FlagSet) {\n\tset.StringVar(&GlobalFlags.SelectedEnv, flagEnv, \"\", \"set which env from the config file to use\")\n\tset.Var(&GlobalFlags.Vars, flagVar, \"input variables\")\n\tset.StringVarP(&GlobalFlags.ConfigURL, flagConfig, \"c\", defaultConfigPath, \"select config (project) file using URL format\")\n}\n\nfunc addFlagAutoApprove(set *pflag.FlagSet, target *bool) {\n\tset.BoolVar(target, flagAutoApprove, false, \"apply changes without prompting for approval\")\n}\n\nfunc addFlagDirFormat(set *pflag.FlagSet, target *string) {\n\tset.StringVar(target, flagDirFormat, \"atlas\", \"select migration file format\")\n}\n\nfunc addFlagLockTimeout(set *pflag.FlagSet, target *time.Duration) {\n\tset.DurationVar(target, flagLockTimeout, 10*time.Second, \"set how long to wait for the database lock\")\n}\n\n// addFlagURL adds a URL flag. If given, args[0] override the name, args[1] the shorthand, args[2] the default value.\nfunc addFlagDirURL(set *pflag.FlagSet, target *string, args ...string) {\n\tname, short, val := flagDirURL, \"\", \"file://migrations\"\n\tswitch len(args) {\n\tcase 3:\n\t\tval = args[2]\n\t\tfallthrough\n\tcase 2:\n\t\tshort = args[1]\n\t\tfallthrough\n\tcase 1:\n\t\tname = args[0]\n\t}\n\tset.StringVarP(target, name, short, val, \"select migration directory using URL format\")\n}\n\nfunc addFlagDevURL(set *pflag.FlagSet, target *string) {\n\tset.StringVar(\n\t\ttarget,\n\t\tflagDevURL,\n\t\t\"\",\n\t\t\"[driver://username:password@address/dbname?param=value] select a dev database using the URL format\",\n\t)\n}\n\nfunc addFlagDryRun(set *pflag.FlagSet, target *bool) {\n\tset.BoolVar(target, flagDryRun, false, \"print SQL without executing it\")\n}\n\nfunc addFlagExclude(set *pflag.FlagSet, target *[]string) {\n\tset.StringSliceVar(\n\t\ttarget,\n\t\tflagExclude,\n\t\tnil,\n\t\t\"list of glob patterns used to filter resources from applying\",\n\t)\n}\n\nfunc addFlagInclude(set *pflag.FlagSet, target *[]string) {\n\tset.StringSliceVar(\n\t\ttarget,\n\t\tflagInclude,\n\t\tnil,\n\t\t\"list of glob patterns used to select which resources to keep in inspection\",\n\t)\n}\n\nfunc addFlagLog(set *pflag.FlagSet, target *string) {\n\tset.StringVar(target, flagLog, \"\", \"Go template to use to format the output\")\n\t// Use MarkHidden instead of MarkDeprecated to avoid\n\t// spam users' system logs with deprecation warnings.\n\tcobra.CheckErr(set.MarkHidden(flagLog))\n}\n\nfunc addFlagFormat(set *pflag.FlagSet, target *string) {\n\tset.StringVar(target, flagFormat, \"\", \"Go template to use to format the output\")\n}\n\nfunc addFlagRevisionSchema(set *pflag.FlagSet, target *string) {\n\tset.StringVar(target, flagRevisionSchema, \"\", \"name of the schema the revisions table resides in\")\n}\n\nfunc addFlagSchemas(set *pflag.FlagSet, target *[]string) {\n\tset.StringSliceVarP(\n\t\ttarget,\n\t\tflagSchema, flagSchemaShort,\n\t\tnil,\n\t\t\"set schema names\",\n\t)\n}\n\n// addFlagURL adds a URL flag. If given, args[0] override the name, args[1] the shorthand.\nfunc addFlagURL(set *pflag.FlagSet, target *string, args ...string) {\n\tname, short := flagURL, flagURLShort\n\tswitch len(args) {\n\tcase 2:\n\t\tshort = args[1]\n\t\tfallthrough\n\tcase 1:\n\t\tname = args[0]\n\t}\n\tset.StringVarP(\n\t\ttarget,\n\t\tname, short,\n\t\t\"\",\n\t\t\"[driver://username:password@address/dbname?param=value] select a resource using the URL format\",\n\t)\n}\n\nfunc addFlagURLs(set *pflag.FlagSet, target *[]string, args ...string) {\n\tname, short := flagURL, flagURLShort\n\tswitch len(args) {\n\tcase 2:\n\t\tshort = args[1]\n\t\tfallthrough\n\tcase 1:\n\t\tname = args[0]\n\t}\n\tset.StringSliceVarP(\n\t\ttarget,\n\t\tname, short,\n\t\tnil,\n\t\t\"[driver://username:password@address/dbname?param=value] select a resource using the URL format\",\n\t)\n}\n\nfunc addFlagToURLs(set *pflag.FlagSet, target *[]string) {\n\tset.StringSliceVarP(target, flagTo, \"\", nil, \"[driver://username:password@address/dbname?param=value] select a desired state using the URL format\")\n}\n\n// maySetFlag sets the flag with the provided name to envVal if such a flag exists\n// on the cmd, it was not set by the user via the command line and if envVal is not\n// an empty string.\nfunc maySetFlag(cmd *cobra.Command, name, envVal string) error {\n\tif f := cmd.Flag(name); f == nil || f.Changed || envVal == \"\" {\n\t\treturn nil\n\t}\n\treturn cmd.Flags().Set(name, envVal)\n}\n\n// resetFromEnv traverses the command flags, records what flags\n// were not set by the user and returns a callback to clear them\n// after it was set by the current environment.\nfunc resetFromEnv(cmd *cobra.Command) func() {\n\tmayReset := make(map[string]func() error)\n\tcmd.Flags().VisitAll(func(f *pflag.Flag) {\n\t\tif f.Changed {\n\t\t\treturn\n\t\t}\n\t\tvs := f.Value.String()\n\t\tr := func() error { return f.Value.Set(vs) }\n\t\tif v, ok := f.Value.(*Vars); ok {\n\t\t\tvs := v.Copy()\n\t\t\tr = func() error {\n\t\t\t\tv.Replace(vs.Copy())\n\t\t\t\treturn nil\n\t\t\t}\n\t\t} else if v, ok := f.Value.(pflag.SliceValue); ok {\n\t\t\tvs := v.GetSlice()\n\t\t\tr = func() error {\n\t\t\t\treturn v.Replace(vs)\n\t\t\t}\n\t\t}\n\t\tmayReset[f.Name] = r\n\t})\n\treturn func() {\n\t\tfor name, reset := range mayReset {\n\t\t\tif f := cmd.Flag(name); f != nil && f.Changed {\n\t\t\t\tf.Changed = false\n\t\t\t\t// Unexpected error, because this flag was set before.\n\t\t\t\tcobra.CheckErr(reset())\n\t\t\t}\n\t\t}\n\t}\n}\n\n// stateReaderConfig is given to stateReader.\ntype stateReaderConfig struct {\n\turls        []string          // urls to create a migrate.StateReader from\n\tclient, dev *sqlclient.Client // database connections, while dev is considered a dev database, client is not\n\tschemas     []string          // schemas to work on\n\texclude     []string          // exclude flag values\n\tinclude     []string          // include flag values\n\twithPos     bool              // indicate if schema.Pos should be loaded.\n\tvars        Vars\n}\n\n// Exported is a temporary method to convert the stateReaderConfig to cmdext.StateReaderConfig.\nfunc (c *stateReaderConfig) Exported() (*cmdext.StateReaderConfig, error) {\n\tvar (\n\t\terr    error\n\t\tparsed = make([]*url.URL, len(c.urls))\n\t)\n\tfor i, u := range c.urls {\n\t\tif parsed[i], err = sqlclient.ParseURL(u); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn &cmdext.StateReaderConfig{\n\t\tURLs:    parsed,\n\t\tClient:  c.client,\n\t\tDev:     c.dev,\n\t\tSchemas: c.schemas,\n\t\tExclude: c.exclude,\n\t\tInclude: c.include,\n\t\tWithPos: c.withPos,\n\t\tVars:    c.vars,\n\t}, nil\n}\n\n// readerUseDev reports if any of the URL uses the dev-database.\nfunc readerUseDev(env *Env, urls ...string) (bool, error) {\n\ts, err := selectScheme(urls)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tswitch {\n\tcase s == envAttrScheme && env != nil && len(urls) == 1:\n\t\tu, err := env.VarFromURL(urls[0])\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\t// No circular reference possible with env:// variable.\n\t\treturn readerUseDev(env, u)\n\tcase s == cmdext.SchemaTypeFile, s == cmdext.SchemaTypeAtlas:\n\t\treturn true, nil\n\tdefault:\n\t\treturn cmdext.States.HasLoader(s), nil\n\t}\n}\n\n// stateReader returns a migrate.StateReader that reads the state from the given urls.\nfunc stateReader(ctx context.Context, env *Env, config *stateReaderConfig) (*cmdext.StateReadCloser, error) {\n\texcfg, err := config.Exported()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tscheme, err := selectScheme(config.urls)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch scheme {\n\t// \"file\" scheme is valid for both migration directory and HCL paths.\n\tcase cmdext.SchemaTypeFile:\n\t\tswitch ext, err := cmdext.FilesExt(excfg.URLs); {\n\t\tcase err != nil:\n\t\t\treturn nil, err\n\t\tcase ext == cmdext.FileTypeHCL:\n\t\t\treturn cmdext.StateReaderHCL(ctx, excfg)\n\t\tcase ext == cmdext.FileTypeSQL:\n\t\t\treturn cmdext.StateReaderSQL(ctx, excfg)\n\t\tdefault:\n\t\t\tpanic(\"unreachable\") // checked by filesExt.\n\t\t}\n\t// \"atlas\" scheme represents an Atlas Cloud schema.\n\tcase cmdext.SchemaTypeAtlas:\n\t\treturn cmdext.StateReaderAtlas(ctx, excfg)\n\t// \"env\" scheme represents an attribute defined\n\t// on the selected environment.\n\tcase envAttrScheme:\n\t\tswitch {\n\t\tcase GlobalFlags.SelectedEnv == \"\":\n\t\t\treturn nil, errors.New(\"cannot use env:// variables without selecting an environment\")\n\t\tcase len(config.urls) != 1:\n\t\t\treturn nil, errors.New(\"cannot use multiple env:// variables in a single flag\")\n\t\tdefault:\n\t\t\tu, err := env.VarFromURL(config.urls[0])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tcfg := *config\n\t\t\tcfg.urls = []string{u}\n\t\t\treturn stateReader(ctx, env, &cfg)\n\t\t}\n\tdefault:\n\t\t// In case there is an external state-loader registered with this scheme.\n\t\tif l, ok := cmdext.States.Loader(scheme); ok {\n\t\t\trc, err := l.LoadState(ctx, excfg)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn rc, nil\n\t\t}\n\t\t// All other schemes are database (or docker) connections.\n\t\tc, err := env.openClient(ctx, config.urls[0]) // call to selectScheme already checks for len > 0\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tvar sr migrate.StateReader\n\t\tswitch c.URL.Schema {\n\t\tcase \"\":\n\t\t\tsr = migrate.RealmConn(c.Driver, &schema.InspectRealmOption{\n\t\t\t\tSchemas: config.schemas,\n\t\t\t\tExclude: config.exclude,\n\t\t\t\tInclude: config.include,\n\t\t\t})\n\t\tdefault:\n\t\t\tsr = migrate.SchemaConn(c.Driver, c.URL.Schema, &schema.InspectOptions{\n\t\t\t\tExclude: config.exclude,\n\t\t\t\tInclude: config.include,\n\t\t\t})\n\t\t}\n\t\treturn &cmdext.StateReadCloser{\n\t\t\tStateReader: sr,\n\t\t\tCloser:      c,\n\t\t\tSchema:      c.URL.Schema,\n\t\t}, nil\n\t}\n}\n\nconst localStateFile = \"local-community.json\"\n\n// LocalState keeps track of local state to enhance developer experience.\ntype LocalState struct {\n\tUpgradeSuggested time.Time `json:\"v1.us\"`\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/cmdapi_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage cmdapi\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"testing\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdext\"\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdlog\"\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdstate\"\n\tcmdmigrate \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migratelint\"\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nfunc init() {\n\tschemaCmd := schemaCmd()\n\tschemaCmd.AddCommand(\n\t\tschemaApplyCmd(),\n\t\tschemaCleanCmd(),\n\t\tschemaDiffCmd(),\n\t\tschemaFmtCmd(),\n\t\tschemaInspectCmd(),\n\t\tunsupportedCommand(\"schema\", \"test\"),\n\t\tunsupportedCommand(\"schema\", \"plan\"),\n\t\tunsupportedCommand(\"schema\", \"push\"),\n\t)\n\tRoot.AddCommand(schemaCmd)\n\tmigrateCmd := migrateCmd()\n\tmigrateCmd.AddCommand(\n\t\tmigrateApplyCmd(),\n\t\tmigrateDiffCmd(),\n\t\tmigrateHashCmd(),\n\t\tmigrateImportCmd(),\n\t\tmigrateLintCmd(),\n\t\tmigrateNewCmd(),\n\t\tmigrateSetCmd(),\n\t\tmigrateStatusCmd(),\n\t\tmigrateValidateCmd(),\n\t\tunsupportedCommand(\"migrate\", \"checkpoint\"),\n\t\tunsupportedCommand(\"migrate\", \"down\"),\n\t\tunsupportedCommand(\"migrate\", \"rebase\"),\n\t\tunsupportedCommand(\"migrate\", \"rm\"),\n\t\tunsupportedCommand(\"migrate\", \"edit\"),\n\t\tunsupportedCommand(\"migrate\", \"push\"),\n\t\tunsupportedCommand(\"migrate\", \"test\"),\n\t)\n\tRoot.AddCommand(migrateCmd)\n}\n\n// unsupportedCommand create a stub command that reports\n// the command is not supported by this build.\nfunc unsupportedCommand(cmd, sub string) *cobra.Command {\n\ts := unsupportedMessage(cmd, sub)\n\tc := &cobra.Command{\n\t\tHidden: true,\n\t\tUse:    fmt.Sprintf(\"%s is not supported by this build\", sub),\n\t\tShort:  s,\n\t\tLong:   s,\n\t\tRunE: RunE(func(*cobra.Command, []string) error {\n\t\t\treturn AbortErrorf(\"%s\", s)\n\t\t}),\n\t}\n\tc.SetHelpTemplate(s + \"\\n\")\n\treturn c\n}\n\n// unsupportedMessage returns a message informing the user that the command\n// or one of its options are not supported. For example:\n//\n// unsupportedMessage(\"migrate\", \"checkpoint\")\n// unsupportedMessage(\"schema\", \"apply --plan\")\nfunc unsupportedMessage(cmd, sub string) string {\n\treturn fmt.Sprintf(\n\t\t`'atlas %s %s' is not supported by the community version.\n\nTo install the non-community version of Atlas, use the following command:\n\n\tcurl -sSf https://atlasgo.sh | sh\n\nOr, visit the website to see all installation options:\n\n\thttps://atlasgo.io/docs#installation\n`,\n\t\tcmd, sub,\n\t)\n}\n\ntype (\n\t// Project represents an atlas.hcl project config file.\n\tProject struct {\n\t\tEnvs  []*Env `spec:\"env\"`  // List of environments\n\t\tLint  *Lint  `spec:\"lint\"` // Optional global lint policy\n\t\tDiff  *Diff  `spec:\"diff\"` // Optional global diff policy\n\t\tTest  *Test  `spec:\"test\"` // Optional test configuration\n\t\tcloud *cmdext.AtlasConfig\n\t}\n)\n\nconst (\n\tenvSkipUpgradeSuggestions = \"ATLAS_NO_UPGRADE_SUGGESTIONS\"\n\toneWeek                   = 7 * 24 * time.Hour\n)\n\n// maySuggestUpgrade informs the user about the limitations of the community edition to stderr\n// at most once a week. The user can disable this message by setting the ATLAS_NO_UPGRADE_SUGGESTIONS\n// environment variable.\nfunc maySuggestUpgrade(cmd *cobra.Command) {\n\tif os.Getenv(envSkipUpgradeSuggestions) != \"\" || testing.Testing() {\n\t\treturn\n\t}\n\tstate := cmdstate.File[LocalState]{Name: localStateFile}\n\tprev, err := state.Read()\n\tif err != nil {\n\t\treturn\n\t}\n\tif time.Since(prev.UpgradeSuggested) < oneWeek {\n\t\treturn\n\t}\n\ts := `Notice: This Atlas edition lacks support for features such as checkpoints,\ntesting, down migrations, and more. Additionally, advanced database objects such as views, \ntriggers, and stored procedures are not supported. To read more: https://atlasgo.io/community-edition\n\nTo install the non-community version of Atlas, use the following command:\n\n\tcurl -sSf https://atlasgo.sh | sh\n\nOr, visit the website to see all installation options:\n\n\thttps://atlasgo.io/docs#installation\n\n`\n\t_ = cmdlog.WarnOnce(cmd.ErrOrStderr(), cmdlog.ColorCyan(s))\n\tprev.UpgradeSuggested = time.Now()\n\t_ = state.Write(prev)\n}\n\n// migrateLintSetFlags allows setting extra flags for the 'migrate lint' command.\nfunc migrateLintSetFlags(*cobra.Command, *migrateLintFlags) {}\n\n// migrateLintRun is the run command for 'migrate lint'.\nfunc migrateLintRun(cmd *cobra.Command, _ []string, flags migrateLintFlags, env *Env) error {\n\tdev, err := sqlclient.Open(cmd.Context(), flags.devURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer dev.Close()\n\tdir, err := cmdmigrate.Dir(cmd.Context(), flags.dirURL, false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar detect migratelint.ChangeDetector\n\tswitch {\n\tcase flags.latest == 0 && flags.gitBase == \"\":\n\t\treturn fmt.Errorf(\"--%s or --%s is required\", flagLatest, flagGitBase)\n\tcase flags.latest > 0 && flags.gitBase != \"\":\n\t\treturn fmt.Errorf(\"--%s and --%s are mutually exclusive\", flagLatest, flagGitBase)\n\tcase flags.latest > 0:\n\t\tdetect = migratelint.LatestChanges(dir, int(flags.latest))\n\tcase flags.gitBase != \"\":\n\t\tdetect, err = migratelint.NewGitChangeDetector(\n\t\t\tdir,\n\t\t\tmigratelint.WithWorkDir(flags.gitDir),\n\t\t\tmigratelint.WithBase(flags.gitBase),\n\t\t\tmigratelint.WithMigrationsPath(dir.(interface{ Path() string }).Path()),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tformat := migratelint.DefaultTemplate\n\tif f := flags.logFormat; f != \"\" {\n\t\tformat, err = template.New(\"format\").Funcs(migratelint.TemplateFuncs).Parse(f)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parse format: %w\", err)\n\t\t}\n\t}\n\taz, err := sqlcheck.AnalyzerFor(dev.Name, env.Lint.Remain())\n\tif err != nil {\n\t\treturn err\n\t}\n\tr := &migratelint.Runner{\n\t\tDev:            dev,\n\t\tDir:            dir,\n\t\tChangeDetector: detect,\n\t\tReportWriter: &migratelint.TemplateWriter{\n\t\t\tT: format,\n\t\t\tW: cmd.OutOrStdout(),\n\t\t},\n\t\tAnalyzers: az,\n\t}\n\terr = r.Run(cmd.Context())\n\t// Print the error in case it was not printed before.\n\tcmd.SilenceErrors = errors.As(err, &migratelint.SilentError{})\n\tcmd.SilenceUsage = cmd.SilenceErrors\n\treturn err\n}\n\nfunc migrateDiffRun(cmd *cobra.Command, args []string, flags migrateDiffFlags, env *Env) error {\n\tif flags.dryRun {\n\t\treturn errors.New(\"'--dry-run' is not supported in the community version\")\n\t}\n\tctx := cmd.Context()\n\tdev, err := sqlclient.Open(ctx, flags.devURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer dev.Close()\n\t// Acquire a lock.\n\tunlock, err := dev.Lock(ctx, \"atlas_migrate_diff\", flags.lockTimeout)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"acquiring database lock: %w\", err)\n\t}\n\t// If unlocking fails notify the user about it.\n\tdefer func() { cobra.CheckErr(unlock()) }()\n\t// Open the migration directory.\n\tu, err := url.Parse(flags.dirURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdir, err := cmdmigrate.DirURL(ctx, u, false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif flags.edit {\n\t\tl, ok := dir.(*migrate.LocalDir)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"--edit flag supports only atlas directories, but got: %T\", dir)\n\t\t}\n\t\tdir = &editDir{l}\n\t}\n\tvar name, indent string\n\tif len(args) > 0 {\n\t\tname = args[0]\n\t}\n\tf, err := cmdmigrate.Formatter(u)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif f, indent, err = mayIndent(u, f, flags.format); err != nil {\n\t\treturn err\n\t}\n\tdiffOpts := diffOptions(cmd, env)\n\t// If there is a state-loader that requires a custom\n\t// 'migrate diff' handling, offload it the work.\n\tif d, ok := cmdext.States.Differ(flags.desiredURLs); ok {\n\t\terr := d.MigrateDiff(ctx, &cmdext.MigrateDiffOptions{\n\t\t\tTo:      flags.desiredURLs,\n\t\t\tName:    name,\n\t\t\tIndent:  indent,\n\t\t\tDir:     dir,\n\t\t\tDev:     dev,\n\t\t\tOptions: diffOpts,\n\t\t})\n\t\treturn maskNoPlan(cmd, err)\n\t}\n\t// Get a state reader for the desired state.\n\tdesired, err := stateReader(ctx, env, &stateReaderConfig{\n\t\turls:    flags.desiredURLs,\n\t\tdev:     dev,\n\t\tclient:  dev,\n\t\tschemas: flags.schemas,\n\t\tvars:    env.Vars(),\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer desired.Close()\n\topts := []migrate.PlannerOption{\n\t\tmigrate.PlanFormat(f),\n\t\tmigrate.PlanWithIndent(indent),\n\t\tmigrate.PlanWithDiffOptions(diffOpts...),\n\t}\n\tif dev.URL.Schema != \"\" {\n\t\t// Disable tables qualifier in schema-mode.\n\t\topts = append(opts, migrate.PlanWithSchemaQualifier(flags.qualifier))\n\t}\n\t// Plan the changes and create a new migration file.\n\tpl := migrate.NewPlanner(dev.Driver, dir, opts...)\n\tplan, err := func() (*migrate.Plan, error) {\n\t\tif dev.URL.Schema != \"\" {\n\t\t\treturn pl.PlanSchema(ctx, name, desired.StateReader)\n\t\t}\n\t\treturn pl.Plan(ctx, name, desired.StateReader)\n\t}()\n\tvar cerr *migrate.NotCleanError\n\tswitch {\n\tcase errors.As(err, &cerr) && dev.URL.Schema == \"\" && desired.Schema != \"\":\n\t\treturn fmt.Errorf(\"dev database is not clean (%s). Add a schema to the URL to limit the scope of the connection\", cerr.Reason)\n\tcase err != nil:\n\t\treturn maskNoPlan(cmd, err)\n\tdefault:\n\t\treturn pl.WritePlan(plan)\n\t}\n}\n\n// schemaApplyRunE is the community version of the 'atlas schema apply' command.\nfunc schemaApplyRunE(cmd *cobra.Command, _ []string, flags *schemaApplyFlags) error {\n\tswitch {\n\tcase flags.edit:\n\t\treturn AbortErrorf(\"%s\", unsupportedMessage(\"schema\", \"apply --edit\"))\n\tcase flags.planURL != \"\":\n\t\treturn AbortErrorf(\"%s\", unsupportedMessage(\"schema\", \"apply --plan\"))\n\tcase len(flags.include) > 0:\n\t\treturn AbortErrorf(\"%s\", unsupportedMessage(\"schema\", \"apply --include\"))\n\tcase GlobalFlags.SelectedEnv == \"\":\n\t\tenv, err := selectEnv(cmd)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn schemaApplyRun(cmd, *flags, env)\n\tdefault:\n\t\t_, envs, err := EnvByName(cmd, GlobalFlags.SelectedEnv, GlobalFlags.Vars)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(envs) != 1 {\n\t\t\treturn fmt.Errorf(\"multi-environment %q is not supported\", GlobalFlags.SelectedEnv)\n\t\t}\n\t\tif err := setSchemaEnvFlags(cmd, envs[0]); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn schemaApplyRun(cmd, *flags, envs[0])\n\t}\n}\n\nfunc schemaApplyRun(cmd *cobra.Command, flags schemaApplyFlags, env *Env) error {\n\tvar (\n\t\terr    error\n\t\tctx    = cmd.Context()\n\t\tdev    *sqlclient.Client\n\t\tformat = cmdlog.SchemaPlanTemplate\n\t)\n\tif err = flags.check(env); err != nil {\n\t\treturn err\n\t}\n\tif v := flags.logFormat; v != \"\" {\n\t\tif !flags.dryRun && !flags.autoApprove {\n\t\t\treturn errors.New(`--log and --format can only be used with --dry-run or --auto-approve`)\n\t\t}\n\t\tif format, err = template.New(\"format\").Funcs(cmdlog.ApplyTemplateFuncs).Parse(v); err != nil {\n\t\t\treturn fmt.Errorf(\"parse log format: %w\", err)\n\t\t}\n\t}\n\tif flags.devURL != \"\" {\n\t\tif dev, err = sqlclient.Open(ctx, flags.devURL); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer dev.Close()\n\t}\n\tfrom, err := stateReader(ctx, env, &stateReaderConfig{\n\t\turls:    []string{flags.url},\n\t\tschemas: flags.schemas,\n\t\texclude: flags.exclude,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer from.Close()\n\tclient, ok := from.Closer.(*sqlclient.Client)\n\tif !ok {\n\t\treturn errors.New(\"--url must be a database connection\")\n\t}\n\tto, err := stateReader(ctx, env, &stateReaderConfig{\n\t\turls:    flags.toURLs,\n\t\tdev:     dev,\n\t\tclient:  client,\n\t\tschemas: flags.schemas,\n\t\texclude: flags.exclude,\n\t\tvars:    env.Vars(),\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer to.Close()\n\tdiff, err := computeDiff(ctx, client, from, to, diffOptions(cmd, env)...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tmaySuggestUpgrade(cmd)\n\t// Returning at this stage should\n\t// not trigger the help message.\n\tcmd.SilenceUsage = true\n\tswitch changes := diff.changes; {\n\tcase len(changes) == 0:\n\t\treturn format.Execute(cmd.OutOrStdout(), &cmdlog.SchemaApply{})\n\tcase flags.logFormat != \"\" && flags.autoApprove:\n\t\tvar (\n\t\t\tapplied int\n\t\t\tplan    *migrate.Plan\n\t\t\tcause   *cmdlog.StmtError\n\t\t\tout     = cmd.OutOrStdout()\n\t\t)\n\t\tif plan, err = client.PlanChanges(ctx, \"\", changes, planOptions(client)...); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err = applyChanges(ctx, client, changes, flags.txMode); err == nil {\n\t\t\tapplied = len(plan.Changes)\n\t\t} else if i, ok := err.(interface{ Applied() int }); ok && i.Applied() < len(plan.Changes) {\n\t\t\tapplied, cause = i.Applied(), &cmdlog.StmtError{Stmt: plan.Changes[i.Applied()].Cmd, Text: err.Error()}\n\t\t} else {\n\t\t\tcause = &cmdlog.StmtError{Text: err.Error()}\n\t\t}\n\t\terr1 := format.Execute(out, cmdlog.NewSchemaApply(ctx, cmdlog.NewEnv(client, nil), plan.Changes[:applied], plan.Changes[applied:], cause))\n\t\treturn errors.Join(err, err1)\n\tdefault:\n\t\tswitch err := summary(cmd, client, changes, format); {\n\t\tcase err != nil:\n\t\t\treturn err\n\t\tcase flags.dryRun:\n\t\t\treturn nil\n\t\tcase flags.autoApprove:\n\t\t\treturn applyChanges(ctx, client, changes, flags.txMode)\n\t\tdefault:\n\t\t\treturn promptApply(cmd, flags, diff, client, dev)\n\t\t}\n\t}\n}\n\n// applySchemaClean is the community-version of the 'atlas schema clean' handler.\nfunc applySchemaClean(cmd *cobra.Command, client *sqlclient.Client, drop []schema.Change, flags schemaCleanFlags) error {\n\tif flags.dryRun {\n\t\treturn AbortErrorf(\"%s\", unsupportedMessage(\"schema\", \"clean --dry-run\"))\n\t}\n\tif flags.logFormat != \"\" {\n\t\treturn AbortErrorf(\"%s\", unsupportedMessage(\"schema\", \"clean --format\"))\n\t}\n\tif len(drop) == 0 {\n\t\tcmd.Println(\"Nothing to drop\")\n\t\treturn nil\n\t}\n\tif err := summary(cmd, client, drop, cmdlog.SchemaPlanTemplate); err != nil {\n\t\treturn err\n\t}\n\tif flags.autoApprove || promptUser(cmd) {\n\t\tif err := client.ApplyChanges(cmd.Context(), drop); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc schemaDiffRun(cmd *cobra.Command, _ []string, flags schemaDiffFlags, env *Env) error {\n\tvar (\n\t\tctx = cmd.Context()\n\t\tc   *sqlclient.Client\n\t)\n\tif len(flags.include) > 0 {\n\t\treturn AbortErrorf(\"%s\", unsupportedMessage(\"schema\", \"diff --include\"))\n\t}\n\t// We need a driver for diffing and planning. If given, dev database has precedence.\n\tif flags.devURL != \"\" {\n\t\tvar err error\n\t\tc, err = sqlclient.Open(ctx, flags.devURL)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer c.Close()\n\t}\n\tfrom, err := stateReader(ctx, env, &stateReaderConfig{\n\t\turls:    flags.fromURL,\n\t\tdev:     c,\n\t\tvars:    env.Vars(),\n\t\tschemas: flags.schemas,\n\t\texclude: flags.exclude,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer from.Close()\n\tto, err := stateReader(ctx, env, &stateReaderConfig{\n\t\turls:    flags.toURL,\n\t\tdev:     c,\n\t\tvars:    env.Vars(),\n\t\tschemas: flags.schemas,\n\t\texclude: flags.exclude,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer to.Close()\n\tif c == nil {\n\t\t// If not both states are provided by a database connection, the call to state-reader would have returned\n\t\t// an error already. If we land in this case, we can assume both states are database connections.\n\t\tc = to.Closer.(*sqlclient.Client)\n\t}\n\tformat := cmdlog.SchemaDiffTemplate\n\tif v := flags.format; v != \"\" {\n\t\tif format, err = template.New(\"format\").Funcs(cmdlog.SchemaDiffFuncs).Parse(v); err != nil {\n\t\t\treturn fmt.Errorf(\"parse log format: %w\", err)\n\t\t}\n\t}\n\tdiff, err := computeDiff(ctx, c, from, to, diffOptions(cmd, env)...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tmaySuggestUpgrade(cmd)\n\treturn format.Execute(cmd.OutOrStdout(),\n\t\tcmdlog.NewSchemaDiff(ctx, c, diff.from, diff.to, diff.changes),\n\t)\n}\n\nfunc summary(cmd *cobra.Command, c *sqlclient.Client, changes []schema.Change, t *template.Template) error {\n\tp, err := c.PlanChanges(cmd.Context(), \"\", changes, planOptions(c)...)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn t.Execute(\n\t\tcmd.OutOrStdout(),\n\t\tcmdlog.NewSchemaPlan(cmd.Context(), cmdlog.NewEnv(c, nil), p.Changes, nil),\n\t)\n}\n\nfunc promptApply(cmd *cobra.Command, flags schemaApplyFlags, diff *diff, client, _ *sqlclient.Client) error {\n\tif !flags.dryRun && (flags.autoApprove || promptUser(cmd)) {\n\t\treturn applyChanges(cmd.Context(), client, diff.changes, flags.txMode)\n\t}\n\treturn nil\n}\n\nfunc maySetLoginContext(*cobra.Command, *Project) error {\n\treturn nil\n}\n\nfunc setEnvs(context.Context, []*Env) {}\n\n// specOptions are the options for the schema spec.\nvar specOptions []schemahcl.Option\n\n// diffOptions returns environment-aware diff options.\nfunc diffOptions(_ *cobra.Command, env *Env) []schema.DiffOption {\n\treturn append(env.DiffOptions(), schema.DiffNormalized())\n}\n\n// openClient allows opening environment-aware clients.\nfunc (*Env) openClient(ctx context.Context, u string) (*sqlclient.Client, error) {\n\treturn sqlclient.Open(ctx, u)\n}\n\ntype schemaInspectFlags struct {\n\turl       string   // URL of resource to inspect.\n\tdevURL    string   // URL of the dev database.\n\tlogFormat string   // Format of the log output.\n\tschemas   []string // Schemas to take into account when diffing.\n\texclude   []string // List of glob patterns used to filter resources from applying (see schema.InspectOptions).\n}\n\n// schemaInspectCmd represents the 'atlas schema inspect' subcommand.\nfunc schemaInspectCmd() *cobra.Command {\n\tcmd, _ := schemaInspectCmdWithFlags()\n\treturn cmd\n}\n\nfunc schemaInspectCmdWithFlags() (*cobra.Command, *schemaInspectFlags) {\n\tvar (\n\t\tenv   *Env\n\t\tflags schemaInspectFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"inspect\",\n\t\t\tShort: \"Inspect a database and print its schema in Atlas DDL syntax.\",\n\t\t\tLong: `'atlas schema inspect' connects to the given database and inspects its schema.\nIt then prints to the screen the schema of that database in Atlas DDL syntax. This output can be\nsaved to a file, commonly by redirecting the output to a file named with a \".hcl\" suffix:\n\n  atlas schema inspect -u \"mysql://user:pass@localhost:3306/dbname\" > schema.hcl\n\nThis file can then be edited and used with the` + \" `atlas schema apply` \" + `command to plan\nand execute schema migrations against the given database. In cases where users wish to inspect\nall multiple schemas in a given database (for instance a MySQL server may contain multiple named\ndatabases), omit the relevant part from the url, e.g. \"mysql://user:pass@localhost:3306/\".\nTo select specific schemas from the databases, users may use the \"--schema\" (or \"-s\" shorthand)\nflag.\n\t`,\n\t\t\tExample: `  atlas schema inspect -u \"mysql://user:pass@localhost:3306/dbname\"\n  atlas schema inspect -u \"mariadb://user:pass@localhost:3306/\" --schema=schemaA,schemaB -s schemaC\n  atlas schema inspect --url \"postgres://user:pass@host:port/dbname?sslmode=disable\"\n  atlas schema inspect -u \"sqlite://file:ex1.db?_fk=1\"`,\n\t\t\tPreRunE: RunE(func(cmd *cobra.Command, args []string) (err error) {\n\t\t\t\tif env, err = selectEnv(cmd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn setSchemaEnvFlags(cmd, env)\n\t\t\t}),\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\treturn schemaInspectRun(cmd, args, flags, env)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagURL(cmd.Flags(), &flags.url)\n\taddFlagDevURL(cmd.Flags(), &flags.devURL)\n\taddFlagSchemas(cmd.Flags(), &flags.schemas)\n\taddFlagExclude(cmd.Flags(), &flags.exclude)\n\taddFlagLog(cmd.Flags(), &flags.logFormat)\n\taddFlagFormat(cmd.Flags(), &flags.logFormat)\n\tcobra.CheckErr(cmd.MarkFlagRequired(flagURL))\n\tcmd.MarkFlagsMutuallyExclusive(flagLog, flagFormat)\n\treturn cmd, &flags\n}\n\nfunc schemaInspectRun(cmd *cobra.Command, _ []string, flags schemaInspectFlags, env *Env) error {\n\tvar (\n\t\tctx = cmd.Context()\n\t\tdev *sqlclient.Client\n\t)\n\tuseDev, err := readerUseDev(env, flags.url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif flags.devURL != \"\" && useDev {\n\t\tif dev, err = sqlclient.Open(ctx, flags.devURL); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer dev.Close()\n\t}\n\tr, err := stateReader(ctx, env, &stateReaderConfig{\n\t\turls:    []string{flags.url},\n\t\tdev:     dev,\n\t\tvars:    env.Vars(),\n\t\tschemas: flags.schemas,\n\t\texclude: flags.exclude,\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer r.Close()\n\tclient, ok := r.Closer.(*sqlclient.Client)\n\tif !ok && dev != nil {\n\t\tclient = dev\n\t}\n\tformat := cmdlog.SchemaInspectTemplate\n\tif v := flags.logFormat; v != \"\" {\n\t\tif format, err = template.New(\"format\").Funcs(cmdlog.InspectTemplateFuncs).Parse(v); err != nil {\n\t\t\treturn fmt.Errorf(\"parse log format: %w\", err)\n\t\t}\n\t}\n\ts, err := r.ReadState(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tmaySuggestUpgrade(cmd)\n\ti := cmdlog.NewSchemaInspect(ctx, client, s)\n\ti.URL = flags.url\n\treturn format.Execute(cmd.OutOrStdout(), i)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/cmdapi_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdapi\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/sqlite\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestVars_String(t *testing.T) {\n\tvar vs Vars\n\trequire.Equal(t, \"[]\", vs.String())\n\trequire.NoError(t, vs.Set(\"a=b\"))\n\trequire.Equal(t, \"[a:b]\", vs.String())\n\trequire.NoError(t, vs.Set(\"b=c\"))\n\trequire.Equal(t, \"[a:b, b:c]\", vs.String())\n\trequire.NoError(t, vs.Set(\"a=d\"))\n\trequire.Equal(t, \"[a:[b, d], b:c]\", vs.String(), \"multiple values of the same key: --var url=<one> --var url=<two>\")\n}\n\nfunc runCmd(cmd *cobra.Command, args ...string) (string, error) {\n\treturn runCmdContext(context.Background(), cmd, args...)\n}\n\nfunc runCmdContext(ctx context.Context, cmd *cobra.Command, args ...string) (string, error) {\n\tvar out bytes.Buffer\n\tcmd.SetOut(&out)\n\tcmd.SetErr(&out)\n\t// Cobra checks for the args to equal nil and if so uses os.Args[1:].\n\t// In tests, this leads to go tooling arguments being part of the command arguments.\n\tif args == nil {\n\t\targs = []string{}\n\t}\n\tcmd.SetArgs(args)\n\terr := cmd.ExecuteContext(ctx)\n\treturn out.String(), err\n}\n\n// openSQLite creates a sqlite db, seeds it with the seed query and returns the url to it.\nfunc openSQLite(t *testing.T, seed string) string {\n\tf, err := os.CreateTemp(\"\", \"sqlite.db\")\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, os.Remove(f.Name()))\n\t})\n\tdsn := fmt.Sprintf(\"file:%s?cache=shared&_fk=1\", f.Name())\n\tdb, err := sql.Open(\"sqlite3\", dsn)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, db.Close())\n\t})\n\tdrv, err := sqlite.Open(db)\n\trequire.NoError(t, err)\n\tif seed != \"\" {\n\t\t_, err := drv.ExecContext(context.Background(), seed)\n\t\trequire.NoError(t, err)\n\t}\n\treturn fmt.Sprintf(\"sqlite://%s\", dsn)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/migrate.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdapi\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/template\"\n\t\"text/template/parse\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cloudapi\"\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdext\"\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdlog\"\n\tcmdmigrate \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t\"ariga.io/atlas/sql/sqltool\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/spf13/cobra\"\n)\n\n// migrateCmd represents the subcommand 'atlas migrate'.\nfunc migrateCmd() *cobra.Command {\n\tcmd := &cobra.Command{\n\t\tUse:   \"migrate\",\n\t\tShort: \"Manage versioned migration files\",\n\t\tLong:  \"'atlas migrate' wraps several sub-commands for migration management.\",\n\t}\n\taddGlobalFlags(cmd.PersistentFlags())\n\treturn cmd\n}\n\ntype migrateApplyFlags struct {\n\turl             string\n\tdirURL          string\n\trevisionSchema  string\n\tdryRun          bool\n\tlogFormat       string\n\tlockTimeout     time.Duration\n\tallowDirty      bool   // allow working on a database that already has resources\n\tbaselineVersion string // apply with this version as baseline\n\ttxMode          string // (none, file, all)\n\texecOrder       string // (linear, linear-skip, non-linear)\n\tcontext         string // Run context. See cloudapi.DeployContextInput.\n}\n\nfunc (f *migrateApplyFlags) migrateOptions() ([]migrate.ExecutorOption, error) {\n\tvar opts []migrate.ExecutorOption\n\tif f.allowDirty {\n\t\topts = append(opts, migrate.WithAllowDirty(true))\n\t}\n\tif v := f.baselineVersion; v != \"\" {\n\t\topts = append(opts, migrate.WithBaselineVersion(v))\n\t}\n\tif v := f.execOrder; v != \"\" && v != execOrderLinear {\n\t\tswitch v {\n\t\tcase execOrderLinearSkip:\n\t\t\topts = append(opts, migrate.WithExecOrder(migrate.ExecOrderLinearSkip))\n\t\tcase execOrderNonLinear:\n\t\t\topts = append(opts, migrate.WithExecOrder(migrate.ExecOrderNonLinear))\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown execution order: %q\", v)\n\t\t}\n\t}\n\treturn opts, nil\n}\n\nfunc migrateApplyCmd() *cobra.Command {\n\tvar (\n\t\tflags migrateApplyFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"apply [flags] [amount]\",\n\t\t\tShort: \"Applies pending migration files on the connected database.\",\n\t\t\tLong: `'atlas migrate apply' reads the migration state of the connected database and computes what migrations are pending.\nIt then attempts to apply the pending migration files in the correct order onto the database. \nThe first argument denotes the maximum number of migration files to apply.\nAs a safety measure 'atlas migrate apply' will abort with an error, if:\n  - the migration directory is not in sync with the 'atlas.sum' file\n  - the migration and database history do not match each other\n\nIf run with the \"--dry-run\" flag, atlas will not execute any SQL.`,\n\t\t\tExample: `  atlas migrate apply -u \"mysql://user:pass@localhost:3306/dbname\"\n  atlas migrate apply --dir \"file:///path/to/migration/directory\" --url \"mysql://user:pass@localhost:3306/dbname\" 1\n  atlas migrate apply --env dev 1\n  atlas migrate apply --dry-run --env dev 1`,\n\t\t\tArgs: cobra.MaximumNArgs(1),\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) (cmdErr error) {\n\t\t\t\tswitch {\n\t\t\t\tcase GlobalFlags.SelectedEnv == \"\":\n\t\t\t\t\t// Env not selected, but the\n\t\t\t\t\t// -c flag might be set.\n\t\t\t\t\tenv, err := selectEnv(cmd)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tif err := setMigrateEnvFlags(cmd, env); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\treturn migrateApplyRun(cmd, args, flags, env, &MigrateReport{}) // nop reporter\n\t\t\t\tdefault:\n\t\t\t\t\tproject, envs, err := EnvByName(cmd, GlobalFlags.SelectedEnv, GlobalFlags.Vars)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tset, err := NewReportProvider(cmd.Context(), project, envs, &flags)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tvar hasRemote bool\n\t\t\t\t\tdefer func() {\n\t\t\t\t\t\tif hasRemote {\n\t\t\t\t\t\t\tset.Flush(cmd, cmdErr)\n\t\t\t\t\t\t}\n\t\t\t\t\t}()\n\t\t\t\t\treturn cmdEnvsRun(envs, setMigrateEnvFlags, cmd, func(env *Env) error {\n\t\t\t\t\t\t// Report deployments only if one of the migration directories is a cloud directory.\n\t\t\t\t\t\tif u, err := url.Parse(flags.dirURL); err == nil && u.Scheme == cmdmigrate.DirTypeAtlas {\n\t\t\t\t\t\t\thasRemote = true\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn migrateApplyRun(cmd, args, flags, env, set.ReportFor(flags, env))\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagURL(cmd.Flags(), &flags.url)\n\taddFlagDirURL(cmd.Flags(), &flags.dirURL)\n\taddFlagLog(cmd.Flags(), &flags.logFormat)\n\taddFlagFormat(cmd.Flags(), &flags.logFormat)\n\taddFlagRevisionSchema(cmd.Flags(), &flags.revisionSchema)\n\taddFlagDryRun(cmd.Flags(), &flags.dryRun)\n\taddFlagLockTimeout(cmd.Flags(), &flags.lockTimeout)\n\tcmd.Flags().StringVarP(&flags.baselineVersion, flagBaseline, \"\", \"\", \"start the first migration after the given baseline version\")\n\tcmd.Flags().StringVarP(&flags.txMode, flagTxMode, \"\", txModeFile, \"set transaction mode [none, file, all]\")\n\tcmd.Flags().StringVarP(&flags.execOrder, flagExecOrder, \"\", execOrderLinear, \"set file execution order [linear, linear-skip, non-linear]\")\n\tcmd.Flags().StringVar(&flags.context, flagContext, \"\", \"describes what triggered this command (e.g., GitHub Action)\")\n\tcobra.CheckErr(cmd.Flags().MarkHidden(flagContext))\n\tcmd.Flags().BoolVarP(&flags.allowDirty, flagAllowDirty, \"\", false, \"allow start working on a non-clean database\")\n\tcmd.MarkFlagsMutuallyExclusive(flagLog, flagFormat)\n\treturn cmd\n}\n\ntype (\n\t// MigrateReport responsible for reporting 'migrate apply' reports.\n\tMigrateReport struct {\n\t\tid     string // target id\n\t\tenv    *Env   // nil, if no env set\n\t\tclient *sqlclient.Client\n\t\tlog    *cmdlog.MigrateApply\n\t\trrw    cmdmigrate.RevisionReadWriter\n\t\tdone   func(*cloudapi.ReportMigrationInput)\n\t}\n\t// MigrateReportSet is a set of reports.\n\tMigrateReportSet struct {\n\t\tcloudapi.ReportMigrationSetInput\n\t\tclient *cloudapi.Client\n\t\tdone   int // number of done migrations\n\t}\n)\n\n// NewReportProvider returns a new ReporterProvider.\nfunc NewReportProvider(ctx context.Context, p *Project, envs []*Env, flags *migrateApplyFlags) (*MigrateReportSet, error) {\n\tc := cloudapi.FromContext(ctx)\n\tif p.cloud.Client != nil {\n\t\tc = p.cloud.Client\n\t}\n\ts := &MigrateReportSet{\n\t\tclient: c,\n\t\tReportMigrationSetInput: cloudapi.ReportMigrationSetInput{\n\t\t\tID:        uuid.NewString(),\n\t\t\tStartTime: time.Now(),\n\t\t\tPlanned:   len(envs),\n\t\t},\n\t}\n\tif flags.context != \"\" {\n\t\tif err := json.Unmarshal([]byte(flags.context), &s.Context); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid --context: %w\", err)\n\t\t}\n\t}\n\ts.Step(\"Start migration for %d targets\", len(envs))\n\tfor _, e := range envs {\n\t\ts.StepLog(s.RedactedURL(e.URL))\n\t}\n\treturn s, nil\n}\n\n// RedactedURL returns the redacted URL of the given environment at index i.\nfunc (*MigrateReportSet) RedactedURL(u string) string {\n\tu, err := cloudapi.RedactedURL(u)\n\tif err != nil {\n\t\treturn fmt.Sprintf(\"Error: redacting URL: %v\", err)\n\t}\n\treturn u\n}\n\n// Step starts a new reporting step.\nfunc (s *MigrateReportSet) Step(format string, args ...interface{}) {\n\tif len(s.Log) > 0 && s.Log[len(s.Log)-1].EndTime.IsZero() {\n\t\ts.Log[len(s.Log)-1].EndTime = time.Now()\n\t}\n\ts.Log = append(s.Log, cloudapi.ReportStep{\n\t\tStartTime: time.Now(),\n\t\tText:      fmt.Sprintf(format, args...),\n\t})\n}\n\n// StepLog logs a line to the current reporting step.\nfunc (s *MigrateReportSet) StepLog(text string) {\n\tif len(s.Log) == 0 {\n\t\ts.Step(\"Unnamed step\") // Unexpected.\n\t}\n\ts.Log[len(s.Log)-1].Log = append(s.Log[len(s.Log)-1].Log, cloudapi.ReportStepLog{\n\t\tText: text,\n\t})\n}\n\n// StepLogf logs a line to the current reporting step with formatting.\nfunc (s *MigrateReportSet) StepLogf(format string, args ...interface{}) {\n\ts.StepLog(fmt.Sprintf(format, args...))\n}\n\n// StepLogError logs a line to the current reporting step.\nfunc (s *MigrateReportSet) StepLogError(text string) {\n\tif !strings.HasPrefix(text, \"Error\") {\n\t\ttext = \"Error: \" + text\n\t}\n\ts.StepLog(text)\n\ts.Error = &text\n\ts.Log[len(s.Log)-1].Error = true\n}\n\n// ReportFor returns a new MigrateReport for the given environment.\nfunc (s *MigrateReportSet) ReportFor(flags migrateApplyFlags, e *Env) *MigrateReport {\n\ts.Step(\"Run migration: %d\", s.done+1)\n\ts.StepLogf(\"Target URL: %s\", s.RedactedURL(e.URL))\n\ts.StepLogf(\"Migration directory: %s\", s.RedactedURL(flags.dirURL))\n\treturn &MigrateReport{\n\t\tenv: e,\n\t\tdone: func(r *cloudapi.ReportMigrationInput) {\n\t\t\ts.done++\n\t\t\tr.DryRun = flags.dryRun\n\t\t\ts.Log[len(s.Log)-1].EndTime = time.Now()\n\t\t\tif r.Error != nil && *r.Error != \"\" {\n\t\t\t\ts.StepLogError(*r.Error)\n\t\t\t}\n\t\t\ts.Completed = append(s.Completed, *r)\n\t\t},\n\t}\n}\n\n// Flush report the migration deployment to the cloud.\n// The current implementation is simplistic and sends each\n// report separately without marking them as part of a group.\n//\n// Note that reporting errors are logged, but not cause Atlas to fail.\nfunc (s *MigrateReportSet) Flush(cmd *cobra.Command, cmdErr error) {\n\tif cmdErr != nil && s.Error == nil {\n\t\tvar uerr *url.Error\n\t\tif errors.As(cmdErr, &uerr) {\n\t\t\tuerr.URL = \"\"\n\t\t\tcmdErr = uerr\n\t\t}\n\t\ts.StepLogError(cmdErr.Error())\n\t}\n\tvar (\n\t\terr  error\n\t\tlink string\n\t)\n\tswitch {\n\t// Skip reporting if set is empty,\n\t// or there is no cloud connectivity.\n\tcase s.Planned == 0, s.client == nil:\n\t\treturn\n\t// Single migration that was completed.\n\tcase s.Planned == 1 && len(s.Completed) == 1:\n\t\ts.Completed[0].Context = s.Context\n\t\tlink, err = s.client.ReportMigration(cmd.Context(), s.Completed[0])\n\t// Single migration that failed to start.\n\tcase s.Planned == 1 && len(s.Completed) == 0:\n\t\ts.EndTime = time.Now()\n\t\tlink, err = s.client.ReportMigrationSet(cmd.Context(), s.ReportMigrationSetInput)\n\t// Multi environment migration (e.g., multi-tenancy).\n\tcase s.Planned > 1:\n\t\ts.EndTime = time.Now()\n\t\tlink, err = s.client.ReportMigrationSet(cmd.Context(), s.ReportMigrationSetInput)\n\t}\n\tswitch {\n\tcase err != nil:\n\t\ttxt := fmt.Sprintf(\"Error: %s\", strings.TrimRight(err.Error(), \"\\n\"))\n\t\t// Ensure errors are printed in new lines.\n\t\tif cmd.Flags().Changed(flagFormat) {\n\t\t\ttxt = \"\\n\" + txt\n\t\t}\n\t\tcmd.PrintErrln(txt)\n\t// Unlike errors that are printed to stderr, links are printed to stdout.\n\t// We do it only if the format was not customized by the user (e.g., JSON).\n\tcase link != \"\" && !cmd.Flags().Changed(flagFormat):\n\t\tcmd.Println(link)\n\t}\n}\n\n// Init the report if the necessary dependencies.\nfunc (r *MigrateReport) Init(c *sqlclient.Client, l *cmdlog.MigrateApply, rrw cmdmigrate.RevisionReadWriter) {\n\tr.client, r.log, r.rrw = c, l, rrw\n}\n\n// RecordTargetID asks the revisions-table to allow or provide\n// the target identifier if cloud reporting is enabled.\nfunc (r *MigrateReport) RecordTargetID(ctx context.Context) error {\n\tif r.CloudEnabled(ctx) {\n\t\tid, err := r.rrw.ID(ctx, operatorVersion())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tr.id = id\n\t}\n\treturn nil\n}\n\n// RecordPlanError records any errors that occurred during the planning phase. i.e., when calling to ex.Pending.\nfunc (r *MigrateReport) RecordPlanError(cmd *cobra.Command, flags migrateApplyFlags, planerr string) {\n\tif !r.CloudEnabled(cmd.Context()) {\n\t\treturn\n\t}\n\tvar ver string\n\tif rev, err := r.rrw.CurrentRevision(cmd.Context()); err == nil {\n\t\tver = rev.Version\n\t}\n\tr.done(&cloudapi.ReportMigrationInput{\n\t\tProjectName:  r.env.config.cloud.Project,\n\t\tEnvName:      r.env.Name,\n\t\tDirName:      r.DirName(flags),\n\t\tAtlasVersion: operatorVersion(),\n\t\tTarget: cloudapi.DeployedTargetInput{\n\t\t\tID:     r.id,\n\t\t\tSchema: r.client.URL.Schema,\n\t\t\tURL:    r.client.URL.Redacted(),\n\t\t},\n\t\tStartTime:      r.log.Start,\n\t\tEndTime:        r.log.End,\n\t\tFromVersion:    r.log.Current,\n\t\tToVersion:      r.log.Target,\n\t\tCurrentVersion: ver,\n\t\tError:          &planerr,\n\t\tLog:            planerr,\n\t})\n}\n\n// Done closes and flushes this report.\nfunc (r *MigrateReport) Done(cmd *cobra.Command, flags migrateApplyFlags) error {\n\tif !r.CloudEnabled(cmd.Context()) {\n\t\treturn logApply(cmd, cmd.OutOrStdout(), flags, r.log)\n\t}\n\tvar (\n\t\tver  string\n\t\tclog bytes.Buffer\n\t\terr  = logApply(cmd, io.MultiWriter(cmd.OutOrStdout(), &clog), flags, r.log)\n\t)\n\tswitch rev, err1 := r.rrw.CurrentRevision(cmd.Context()); {\n\tcase errors.Is(err1, migrate.ErrRevisionNotExist):\n\tcase err1 != nil:\n\t\treturn errors.Join(err, err1)\n\tdefault:\n\t\tver = rev.Version\n\t}\n\tr.done(&cloudapi.ReportMigrationInput{\n\t\tProjectName:  r.env.config.cloud.Project,\n\t\tEnvName:      r.env.Name,\n\t\tDirName:      r.DirName(flags),\n\t\tAtlasVersion: operatorVersion(),\n\t\tTarget: cloudapi.DeployedTargetInput{\n\t\t\tID:     r.id,\n\t\t\tSchema: r.client.URL.Schema,\n\t\t\tURL:    r.client.URL.Redacted(),\n\t\t},\n\t\tStartTime:      r.log.Start,\n\t\tEndTime:        r.log.End,\n\t\tFromVersion:    r.log.Current,\n\t\tToVersion:      r.log.Target,\n\t\tCurrentVersion: ver,\n\t\tError: func() *string {\n\t\t\tif r.log.Error != \"\" {\n\t\t\t\treturn &r.log.Error\n\t\t\t}\n\t\t\treturn nil\n\t\t}(),\n\t\tFiles: func() []cloudapi.DeployedFileInput {\n\t\t\tfiles := make([]cloudapi.DeployedFileInput, len(r.log.Applied))\n\t\t\tfor i, f := range r.log.Applied {\n\t\t\t\tf1 := cloudapi.DeployedFileInput{\n\t\t\t\t\tName:      f.Name(),\n\t\t\t\t\tContent:   string(f.Bytes()),\n\t\t\t\t\tStartTime: f.Start,\n\t\t\t\t\tEndTime:   f.End,\n\t\t\t\t\tSkipped:   f.Skipped,\n\t\t\t\t\tApplied:   len(f.Applied),\n\t\t\t\t\tError:     (*cloudapi.StmtErrorInput)(f.Error),\n\t\t\t\t\tChecks:    make([]cloudapi.FileChecksInput, 0, len(f.Checks)),\n\t\t\t\t}\n\t\t\t\tfor _, c := range f.Checks {\n\t\t\t\t\tstmts := make([]cloudapi.CheckStmtInput, 0, len(c.Stmts))\n\t\t\t\t\tfor _, s := range c.Stmts {\n\t\t\t\t\t\tstmts = append(stmts, cloudapi.CheckStmtInput{\n\t\t\t\t\t\t\tStmt:  s.Stmt,\n\t\t\t\t\t\t\tError: s.Error,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t\tf1.Checks = append(f1.Checks, cloudapi.FileChecksInput{\n\t\t\t\t\t\tName:   c.Name,\n\t\t\t\t\t\tStart:  c.Start,\n\t\t\t\t\t\tEnd:    c.End,\n\t\t\t\t\t\tChecks: stmts,\n\t\t\t\t\t\tError:  (*cloudapi.StmtErrorInput)(c.Error),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tfiles[i] = f1\n\t\t\t}\n\t\t\treturn files\n\t\t}(),\n\t\tLog: clog.String(),\n\t})\n\treturn err\n}\n\n// DirName returns the directory name for the report.\nfunc (r *MigrateReport) DirName(flags migrateApplyFlags) string {\n\tdirName := flags.dirURL\n\tswitch u, err := url.Parse(flags.dirURL); {\n\tcase err != nil:\n\t// Local directories are reported as (dangling)\n\t// deployments without a directory.\n\tcase u.Scheme == cmdmigrate.DirTypeFile:\n\t\tdirName = cloudapi.DefaultDirName\n\t// Directory slug.\n\tdefault:\n\t\tdirName = path.Join(u.Host, u.Path)\n\t}\n\treturn dirName\n}\n\n// CloudEnabled reports if cloud reporting is enabled.\nfunc (r *MigrateReport) CloudEnabled(ctx context.Context) bool {\n\tif r.env == nil || r.env.cloud == nil {\n\t\treturn false // The --env was not set.\n\t}\n\tcloud := r.env.cloud\n\t// Cloud reporting is enabled only if there is a cloud connection.\n\treturn cloud.Project != \"\" && (cloud.Client != nil || cloudapi.FromContext(ctx) != nil)\n}\n\nfunc logApply(cmd *cobra.Command, w io.Writer, flags migrateApplyFlags, r *cmdlog.MigrateApply) error {\n\tvar (\n\t\terr error\n\t\tf   = cmdlog.MigrateApplyTemplate\n\t)\n\tif v := flags.logFormat; v != \"\" {\n\t\tf, err = template.New(\"format\").Funcs(cmdlog.ApplyTemplateFuncs).Parse(v)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parse format: %w\", err)\n\t\t}\n\t}\n\tif err = f.Execute(w, r); err != nil {\n\t\treturn fmt.Errorf(\"execute log template: %w\", err)\n\t}\n\t// In case a custom logging was configured, avoid reporting errors twice.\n\t// For example, printing error lines may break parsing the JSON output.\n\tcmd.SilenceErrors = flags.logFormat != \"\"\n\treturn nil\n}\n\ntype migrateDiffFlags struct {\n\tedit              bool\n\tdesiredURLs       []string\n\tdirURL, dirFormat string\n\tdevURL            string\n\tschemas           []string\n\tlockTimeout       time.Duration\n\tformat            string\n\tqualifier         string // optional table qualifier\n\tdryRun            bool\n}\n\n// migrateDiffCmd represents the 'atlas migrate diff' subcommand.\nfunc migrateDiffCmd() *cobra.Command {\n\tvar (\n\t\tflags migrateDiffFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"diff [flags] [name]\",\n\t\t\tShort: \"Compute the diff between the migration directory and a desired state and create a new migration file.\",\n\t\t\tLong: `The 'atlas migrate diff' command uses the dev-database to calculate the current state of the migration directory\nby executing its files. It then compares its state to the desired state and create a new migration file containing\nSQL statements for moving from the current to the desired state. The desired state can be another another database,\nan HCL, SQL, or ORM schema. See: https://atlasgo.io/versioned/diff`,\n\t\t\tExample: `  atlas migrate diff --dev-url \"docker://mysql/8/dev\" --to \"file://schema.hcl\"\n  atlas migrate diff --dev-url \"docker://postgres/15/dev?search_path=public\" --to \"file://atlas.hcl\" add_users_table\n  atlas migrate diff --dev-url \"mysql://user:pass@localhost:3306/dev\" --to \"mysql://user:pass@localhost:3306/dbname\"\n  atlas migrate diff --env dev --format '{{ sql . \"  \" }}'`,\n\t\t\tArgs: cobra.MaximumNArgs(1),\n\t\t\tPreRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\t\tif err := migrateFlagsFromConfig(cmd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := dirFormatBC(flags.dirFormat, &flags.dirURL); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn checkDir(cmd, flags.dirURL, true)\n\t\t\t},\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\tenv, err := selectEnv(cmd)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn migrateDiffRun(cmd, args, flags, env)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagToURLs(cmd.Flags(), &flags.desiredURLs)\n\taddFlagDevURL(cmd.Flags(), &flags.devURL)\n\taddFlagDirURL(cmd.Flags(), &flags.dirURL)\n\taddFlagDirFormat(cmd.Flags(), &flags.dirFormat)\n\taddFlagSchemas(cmd.Flags(), &flags.schemas)\n\taddFlagLockTimeout(cmd.Flags(), &flags.lockTimeout)\n\taddFlagFormat(cmd.Flags(), &flags.format)\n\tcmd.Flags().StringVar(&flags.qualifier, flagQualifier, \"\", \"qualify tables with custom qualifier when working on a single schema\")\n\tcmd.Flags().BoolVarP(&flags.edit, flagEdit, \"\", false, \"edit the generated migration file(s)\")\n\tcmd.Flags().BoolVar(&flags.dryRun, flagDryRun, false, \"print the generated file to stdout instead of writing it to the migration directory\")\n\tcobra.CheckErr(cmd.Flags().MarkHidden(flagDryRun))\n\tcmd.MarkFlagsMutuallyExclusive(flagEdit, flagDryRun)\n\tcobra.CheckErr(cmd.MarkFlagRequired(flagTo))\n\tcobra.CheckErr(cmd.MarkFlagRequired(flagDevURL))\n\treturn cmd\n}\n\nfunc mayIndent(dir *url.URL, f migrate.Formatter, format string) (migrate.Formatter, string, error) {\n\tif format == \"\" {\n\t\treturn f, \"\", nil\n\t}\n\treject := errors.New(`'sql' can only be used to indent statements`)\n\tt, err := template.New(\"format\").\n\t\t// The \"sql\" is a dummy function to detect if the\n\t\t// template was used to indent the SQL statements.\n\t\tFuncs(template.FuncMap{\"sql\": func(...any) (string, error) { return \"\", reject }}).\n\t\tParse(format)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"parse format: %w\", err)\n\t}\n\tindent, ok := func() (string, bool) {\n\t\tif len(t.Tree.Root.Nodes) != 1 {\n\t\t\treturn \"\", false\n\t\t}\n\t\tn, ok := t.Tree.Root.Nodes[0].(*parse.ActionNode)\n\t\tif !ok || len(n.Pipe.Cmds) != 1 || len(n.Pipe.Cmds[0].Args) < 2 || len(n.Pipe.Cmds[0].Args) > 3 {\n\t\t\treturn \"\", false\n\t\t}\n\t\targs := n.Pipe.Cmds[0].Args\n\t\tif args[0].String() != \"sql\" || args[1].String() != \".\" && args[1].String() != \"$\" {\n\t\t\treturn \"\", false\n\t\t}\n\t\td := `\"\"` // empty string as arg.\n\t\tif len(args) == 3 {\n\t\t\td = args[2].String()\n\t\t}\n\t\treturn d, true\n\t}()\n\tif ok {\n\t\tif indent, err = strconv.Unquote(indent); err != nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"parse indent: %w\", err)\n\t\t}\n\t\treturn f, indent, nil\n\t}\n\t// If the template is not an indent, it cannot contain the \"sql\" function.\n\tif err := t.Execute(io.Discard, &migrate.Plan{}); err != nil && errors.Is(err, reject) {\n\t\treturn nil, \"\", fmt.Errorf(\"%v. got: %v\", reject, t.Root.String())\n\t}\n\ttfs := f.(migrate.TemplateFormatter)\n\tif len(tfs) != 1 {\n\t\treturn nil, \"\", fmt.Errorf(\"cannot use format with: %q\", dir.Query().Get(\"format\"))\n\t}\n\treturn migrate.TemplateFormatter{{N: tfs[0].N, C: t}}, \"\", nil\n}\n\n// maskNoPlan masks ErrNoPlan errors.\nfunc maskNoPlan(cmd *cobra.Command, err error) error {\n\tif errors.Is(err, migrate.ErrNoPlan) {\n\t\tcmd.Println(\"The migration directory is synced with the desired state, no changes to be made\")\n\t\treturn nil\n\t}\n\treturn err\n}\n\ntype migrateHashFlags struct{ dirURL, dirFormat string }\n\n// migrateHashCmd represents the 'atlas migrate hash' subcommand.\nfunc migrateHashCmd() *cobra.Command {\n\tvar (\n\t\tflags migrateHashFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"hash [flags]\",\n\t\t\tShort: \"Hash (re-)creates an integrity hash file for the migration directory.\",\n\t\t\tLong: `'atlas migrate hash' computes the integrity hash sum of the migration directory and stores it in the atlas.sum file.\nThis command should be used whenever a manual change in the migration directory was made.`,\n\t\t\tExample: `  atlas migrate hash`,\n\t\t\tPreRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\t\tif err := migrateFlagsFromConfig(cmd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn dirFormatBC(flags.dirFormat, &flags.dirURL)\n\t\t\t},\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\tdir, err := cmdmigrate.Dir(cmd.Context(), flags.dirURL, false)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tsum, err := dir.Checksum()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn migrate.WriteSumFile(dir, sum)\n\t\t\t}),\n\t\t}\n\t)\n\taddFlagDirURL(cmd.Flags(), &flags.dirURL)\n\taddFlagDirFormat(cmd.Flags(), &flags.dirFormat)\n\tcmd.Flags().Bool(\"force\", false, \"\")\n\tcobra.CheckErr(cmd.Flags().MarkDeprecated(\"force\", \"you can safely omit it.\"))\n\treturn cmd\n}\n\ntype migrateImportFlags struct{ fromURL, toURL, dirFormat string }\n\n// migrateImportCmd represents the 'atlas migrate import' subcommand.\nfunc migrateImportCmd() *cobra.Command {\n\tvar (\n\t\tflags migrateImportFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:     \"import [flags]\",\n\t\t\tShort:   \"Import a migration directory from another migration management tool to the Atlas format.\",\n\t\t\tExample: `  atlas migrate import --from \"file:///path/to/source/directory?format=liquibase\" --to \"file:///path/to/migration/directory\"`,\n\t\t\t// Validate the source directory. Consider a directory with no sum file\n\t\t\t// valid, since it might be an import from an existing project.\n\t\t\tPreRunE: func(cmd *cobra.Command, _ []string) error {\n\t\t\t\tif err := migrateFlagsFromConfig(cmd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := dirFormatBC(flags.dirFormat, &flags.fromURL); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\td, err := cmdmigrate.Dir(cmd.Context(), flags.fromURL, false)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err = migrate.Validate(d); err != nil && !errors.Is(err, migrate.ErrChecksumNotFound) {\n\t\t\t\t\tprintChecksumError(cmd, err)\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t},\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\treturn migrateImportRun(cmd, args, flags)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagDirURL(cmd.Flags(), &flags.fromURL, flagFrom)\n\taddFlagDirURL(cmd.Flags(), &flags.toURL, flagTo)\n\taddFlagDirFormat(cmd.Flags(), &flags.dirFormat)\n\treturn cmd\n}\n\nfunc migrateImportRun(cmd *cobra.Command, _ []string, flags migrateImportFlags) error {\n\tp, err := url.Parse(flags.fromURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif f := p.Query().Get(\"format\"); f == \"\" || f == cmdmigrate.FormatAtlas {\n\t\treturn fmt.Errorf(\"cannot import a migration directory already in %q format\", cmdmigrate.FormatAtlas)\n\t}\n\tsrc, err := cmdmigrate.Dir(cmd.Context(), flags.fromURL, false)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttrgt, err := cmdmigrate.Dir(cmd.Context(), flags.toURL, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Target must be empty.\n\tff, err := trgt.Files()\n\tswitch {\n\tcase err != nil:\n\t\treturn err\n\tcase len(ff) != 0:\n\t\treturn errors.New(\"target migration directory must be empty\")\n\t}\n\tff, err = src.Files()\n\tswitch {\n\tcase err != nil:\n\t\treturn err\n\tcase len(ff) == 0:\n\t\tfmt.Fprint(cmd.OutOrStderr(), \"nothing to import\")\n\t\tcmd.SilenceUsage = true\n\t\treturn nil\n\t}\n\t// Fix version numbers for Flyway repeatable migrations.\n\tif _, ok := src.(*sqltool.FlywayDir); ok {\n\t\tsqltool.SetRepeatableVersion(ff)\n\t}\n\t// Extract the statements for each of the migration files,\n\t// add them to a plan to format with the DefaultFormatter.\n\tfor _, f := range ff {\n\t\tstmts, err := f.StmtDecls() // Not driver aware.\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tplan := &migrate.Plan{\n\t\t\tVersion: f.Version(),\n\t\t\tName:    f.Desc(),\n\t\t\tChanges: make([]*migrate.Change, len(stmts)),\n\t\t}\n\t\tvar buf strings.Builder\n\t\tfor i, s := range stmts {\n\t\t\tfor _, c := range s.Comments {\n\t\t\t\tbuf.WriteString(c)\n\t\t\t\tif !strings.HasSuffix(c, \"\\n\") {\n\t\t\t\t\tbuf.WriteString(\"\\n\")\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf.WriteString(strings.TrimSuffix(s.Text, \";\"))\n\t\t\tplan.Changes[i] = &migrate.Change{Cmd: buf.String()}\n\t\t\tbuf.Reset()\n\t\t}\n\t\tfiles, err := migrate.DefaultFormatter.Format(plan)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, f := range files {\n\t\t\tif err := trgt.WriteFile(f.Name(), f.Bytes()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tsum, err := trgt.Checksum()\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn migrate.WriteSumFile(trgt, sum)\n}\n\ntype migrateLintFlags struct {\n\tdirURL, dirFormat string\n\tdevURL            string\n\tlogFormat         string\n\tlatest            uint   // --latest 1\n\tgitBase, gitDir   string // --git-base master --git-dir /path/to/git/repo\n\t// Not enabled by default.\n\tdirBase string // --base atlas://myapp\n\tweb     bool   // Open the web browser\n\tcontext string // Run context. See cloudapi.ContextInput.\n}\n\n// migrateLintCmd represents the 'atlas migrate lint' subcommand.\nfunc migrateLintCmd() *cobra.Command {\n\tvar (\n\t\tenv   *Env\n\t\tflags migrateLintFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"lint [flags]\",\n\t\t\tShort: \"Run analysis on the migration directory\",\n\t\t\tExample: `  atlas migrate lint --env dev\n  atlas migrate lint --dir \"file:///path/to/migrations\" --dev-url \"docker://mysql/8/dev\" --latest 1\n  atlas migrate lint --dir \"file:///path/to/migrations\" --dev-url \"mysql://root:pass@localhost:3306\" --git-base master\n  atlas migrate lint --dir \"file:///path/to/migrations\" --dev-url \"mysql://root:pass@localhost:3306\" --format '{{ json .Files }}'`,\n\t\t\tPreRunE: func(cmd *cobra.Command, args []string) (err error) {\n\t\t\t\tif env, err = selectEnv(cmd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := setMigrateEnvFlags(cmd, env); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn dirFormatBC(flags.dirFormat, &flags.dirURL)\n\t\t\t},\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\treturn migrateLintRun(cmd, args, flags, env)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagDevURL(cmd.Flags(), &flags.devURL)\n\taddFlagDirURL(cmd.Flags(), &flags.dirURL)\n\taddFlagDirFormat(cmd.Flags(), &flags.dirFormat)\n\taddFlagLog(cmd.Flags(), &flags.logFormat)\n\taddFlagFormat(cmd.Flags(), &flags.logFormat)\n\tcmd.Flags().UintVarP(&flags.latest, flagLatest, \"\", 0, \"run analysis on the latest N migration files\")\n\tcmd.Flags().StringVarP(&flags.gitBase, flagGitBase, \"\", \"\", \"run analysis against the base Git branch\")\n\tcmd.Flags().StringVarP(&flags.gitDir, flagGitDir, \"\", \".\", \"path to the repository working directory\")\n\tcobra.CheckErr(cmd.MarkFlagRequired(flagDevURL))\n\tcmd.MarkFlagsMutuallyExclusive(flagLog, flagFormat)\n\tmigrateLintSetFlags(cmd, &flags)\n\treturn cmd\n}\n\ntype migrateNewFlags struct {\n\tedit      bool\n\tdirURL    string\n\tdirFormat string\n}\n\n// migrateNewCmd represents the 'atlas migrate new' subcommand.\nfunc migrateNewCmd() *cobra.Command {\n\tvar (\n\t\tflags migrateNewFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:     \"new [flags] [name]\",\n\t\t\tShort:   \"Creates a new empty migration file in the migration directory.\",\n\t\t\tLong:    `'atlas migrate new' creates a new migration according to the configured formatter without any statements in it.`,\n\t\t\tExample: `  atlas migrate new my-new-migration`,\n\t\t\tArgs:    cobra.MaximumNArgs(1),\n\t\t\tPreRunE: func(cmd *cobra.Command, _ []string) error {\n\t\t\t\tif err := migrateFlagsFromConfig(cmd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := dirFormatBC(flags.dirFormat, &flags.dirURL); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn checkDir(cmd, flags.dirURL, true)\n\t\t\t},\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\treturn migrateNewRun(cmd, args, flags)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagDirURL(cmd.Flags(), &flags.dirURL)\n\taddFlagDirFormat(cmd.Flags(), &flags.dirFormat)\n\tcmd.Flags().BoolVarP(&flags.edit, flagEdit, \"\", false, \"edit the created migration file(s)\")\n\treturn cmd\n}\n\nfunc migrateNewRun(cmd *cobra.Command, args []string, flags migrateNewFlags) error {\n\tu, err := url.Parse(flags.dirURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdir, err := cmdmigrate.DirURL(cmd.Context(), u, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif flags.edit {\n\t\tl, ok := dir.(*migrate.LocalDir)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"--edit flag supports only atlas directories, but got: %T\", dir)\n\t\t}\n\t\tdir = &editDir{l}\n\t}\n\tf, err := cmdmigrate.Formatter(u)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar name string\n\tif len(args) > 0 {\n\t\tname = args[0]\n\t}\n\treturn migrate.NewPlanner(nil, dir, migrate.PlanFormat(f)).WritePlan(&migrate.Plan{Name: name})\n}\n\ntype migrateSetFlags struct {\n\turl               string\n\tdirURL, dirFormat string\n\trevisionSchema    string\n}\n\n// migrateSetCmd represents the 'atlas migrate set' subcommand.\nfunc migrateSetCmd() *cobra.Command {\n\tvar (\n\t\tflags migrateSetFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"set [flags] [version]\",\n\t\t\tShort: \"Set the current version of the migration history table.\",\n\t\t\tLong: `'atlas migrate set' edits the revision table to consider all migrations up to and including the given version\nto be applied. This command is usually used after manually making changes to the managed database.`,\n\t\t\tExample: `  atlas migrate set 3 --url \"mysql://user:pass@localhost:3306/\"\n  atlas migrate set --env local\n  atlas migrate set 1.2.4 --url \"mysql://user:pass@localhost:3306/my_db\" --revision-schema my_revisions`,\n\t\t\tPreRunE: func(cmd *cobra.Command, _ []string) error {\n\t\t\t\tif err := migrateFlagsFromConfig(cmd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := dirFormatBC(flags.dirFormat, &flags.dirURL); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn checkDir(cmd, flags.dirURL, false)\n\t\t\t},\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\treturn migrateSetRun(cmd, args, flags)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagURL(cmd.Flags(), &flags.url)\n\taddFlagDirURL(cmd.Flags(), &flags.dirURL)\n\taddFlagDirFormat(cmd.Flags(), &flags.dirFormat)\n\taddFlagRevisionSchema(cmd.Flags(), &flags.revisionSchema)\n\treturn cmd\n}\n\nfunc migrateSetRun(cmd *cobra.Command, args []string, flags migrateSetFlags) (rerr error) {\n\tctx := cmd.Context()\n\tdir, err := cmdmigrate.Dir(ctx, flags.dirURL, false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tclient, err := sqlclient.Open(ctx, flags.url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer client.Close()\n\t// Acquire a lock.\n\tunlock, err := client.Driver.Lock(ctx, applyLockValue, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"acquiring database lock: %w\", err)\n\t}\n\t// If unlocking fails notify the user about it.\n\tdefer func() { cobra.CheckErr(unlock()) }()\n\tif err := checkRevisionSchemaClarity(cmd, client, flags.revisionSchema); err != nil {\n\t\treturn err\n\t}\n\t// Ensure revision table exists.\n\trrw, err := entRevisions(ctx, client, flags.revisionSchema)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := rrw.Migrate(ctx); err != nil {\n\t\treturn err\n\t}\n\t// Wrap manipulation in a transaction.\n\ttx, err := client.Tx(ctx, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tif rerr == nil {\n\t\t\trerr = tx.Commit()\n\t\t} else if err2 := tx.Rollback(); err2 != nil {\n\t\t\trerr = fmt.Errorf(\"%v: %w\", err2, err)\n\t\t}\n\t}()\n\trrw, err = entRevisions(ctx, tx.Client, flags.revisionSchema)\n\tif err != nil {\n\t\treturn err\n\t}\n\trevs, err := rrw.ReadRevisions(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfiles, err := dir.Files()\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar version string\n\tswitch n := len(args); {\n\t// Prevent the case where 'migrate set' is called without a version on\n\t// a clean database. i.e., we allow only removing or syncing revisions.\n\tcase n == 0 && len(revs) > 0:\n\t\t// Calling set without a version and an empty\n\t\t// migration directory purges the revision table.\n\t\tif len(files) > 0 {\n\t\t\tversion = files[len(files)-1].Version()\n\t\t}\n\tcase n == 1:\n\t\t// Check if the target version does exist in the migration directory.\n\t\tif idx := migrate.FilesLastIndex(files, func(f migrate.File) bool {\n\t\t\treturn f.Version() == args[0]\n\t\t}); idx == -1 {\n\t\t\treturn fmt.Errorf(\"migration with version %q not found\", args[0])\n\t\t}\n\t\tversion = args[0]\n\tdefault:\n\t\treturn fmt.Errorf(\"accepts 1 arg(s), received %d\", n)\n\t}\n\tlog := cmdlog.NewMigrateSet(ctx)\n\tfor _, r := range revs {\n\t\t// Check all existing revisions and ensure they precede the given version. If we encounter a partially\n\t\t// applied revision, or one with errors, mark them \"fixed\".\n\t\tswitch {\n\t\t// remove revision to keep linear history\n\t\tcase r.Version > version:\n\t\t\tlog.Removed(r)\n\t\t\tif err := rrw.DeleteRevision(ctx, r.Version); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t// keep, but if with error mark \"fixed\"\n\t\tcase r.Version == version && (r.Error != \"\" || r.Total != r.Applied):\n\t\t\tlog.Set(r)\n\t\t\tr.Type = migrate.RevisionTypeExecute | migrate.RevisionTypeResolved\n\t\t\tif err := rrw.WriteRevision(ctx, r); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\trevs, err = rrw.ReadRevisions(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// If the target version succeeds the last revision, mark\n\t// migrations applied, until we reach the target version.\n\tvar pending []migrate.File\n\tswitch {\n\tcase len(revs) == 0:\n\t\t// Take every file until we reach target version.\n\t\tfor _, f := range files {\n\t\t\tif f.Version() > version {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tpending = append(pending, f)\n\t\t}\n\tcase version > revs[len(revs)-1].Version:\n\tloop:\n\t\t// Take every file succeeding the last revision until we reach target version.\n\t\tfor _, f := range files {\n\t\t\tswitch {\n\t\t\tcase f.Version() <= revs[len(revs)-1].Version:\n\t\t\t\t// Migration precedes last revision.\n\t\t\tcase f.Version() > version:\n\t\t\t\t// Migration succeeds target revision.\n\t\t\t\tbreak loop\n\t\t\tdefault: // between last revision and target\n\t\t\t\tpending = append(pending, f)\n\t\t\t}\n\t\t}\n\t}\n\t// Mark every pending file as applied.\n\tsum, err := dir.Checksum()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, f := range pending {\n\t\th, err := sum.SumByName(f.Name())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\trev := &migrate.Revision{\n\t\t\tVersion:         f.Version(),\n\t\t\tDescription:     f.Desc(),\n\t\t\tType:            migrate.RevisionTypeResolved,\n\t\t\tExecutedAt:      time.Now(),\n\t\t\tHash:            h,\n\t\t\tOperatorVersion: operatorVersion(),\n\t\t}\n\t\tlog.Set(rev)\n\t\tif err := rrw.WriteRevision(ctx, rev); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif log.Current, err = rrw.CurrentRevision(ctx); err != nil && !errors.Is(err, migrate.ErrRevisionNotExist) {\n\t\treturn err\n\t}\n\treturn cmdlog.MigrateSetTemplate.Execute(cmd.OutOrStdout(), log)\n}\n\ntype migrateStatusFlags struct {\n\turl               string\n\tdirURL, dirFormat string\n\trevisionSchema    string\n\tlogFormat         string\n}\n\n// migrateStatusCmd represents the 'atlas migrate status' subcommand.\nfunc migrateStatusCmd() *cobra.Command {\n\tvar (\n\t\tflags migrateStatusFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"status [flags]\",\n\t\t\tShort: \"Get information about the current migration status.\",\n\t\t\tLong:  `'atlas migrate status' reports information about the current status of a connected database compared to the migration directory.`,\n\t\t\tExample: `  atlas migrate status --url \"mysql://user:pass@localhost:3306/\"\n  atlas migrate status --url \"mysql://user:pass@localhost:3306/\" --dir \"file:///path/to/migration/directory\"`,\n\t\t\tPreRunE: func(cmd *cobra.Command, _ []string) error {\n\t\t\t\tif err := migrateFlagsFromConfig(cmd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := dirFormatBC(flags.dirFormat, &flags.dirURL); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn checkDir(cmd, flags.dirURL, false)\n\t\t\t},\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\treturn migrateStatusRun(cmd, args, flags)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagURL(cmd.Flags(), &flags.url)\n\taddFlagLog(cmd.Flags(), &flags.logFormat)\n\taddFlagFormat(cmd.Flags(), &flags.logFormat)\n\taddFlagDirURL(cmd.Flags(), &flags.dirURL)\n\taddFlagDirFormat(cmd.Flags(), &flags.dirFormat)\n\taddFlagRevisionSchema(cmd.Flags(), &flags.revisionSchema)\n\tcmd.MarkFlagsMutuallyExclusive(flagLog, flagFormat)\n\treturn cmd\n}\n\nfunc migrateStatusRun(cmd *cobra.Command, _ []string, flags migrateStatusFlags) error {\n\tctx := cmd.Context()\n\tdirURL, err := url.Parse(flags.dirURL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse dir-url: %w\", err)\n\t}\n\tdir, err := cmdmigrate.DirURL(ctx, dirURL, false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tclient, err := sqlclient.Open(ctx, flags.url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer client.Close()\n\tif err := checkRevisionSchemaClarity(cmd, client, flags.revisionSchema); err != nil {\n\t\treturn err\n\t}\n\treport, err := (&cmdlog.StatusReporter{\n\t\tClient: client,\n\t\tDir:    dir,\n\t\tDirURL: dirURL,\n\t\tSchema: revisionSchemaName(client, flags.revisionSchema),\n\t}).Report(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tformat := cmdlog.MigrateStatusTemplate\n\tif f := flags.logFormat; f != \"\" {\n\t\tif format, err = template.New(\"format\").Funcs(cmdlog.StatusTemplateFuncs).Parse(f); err != nil {\n\t\t\treturn fmt.Errorf(\"parse format: %w\", err)\n\t\t}\n\t}\n\treturn format.Execute(cmd.OutOrStdout(), report)\n}\n\ntype migrateValidateFlags struct {\n\tdevURL            string\n\tdirURL, dirFormat string\n}\n\n// migrateValidateCmd represents the 'atlas migrate validate' subcommand.\nfunc migrateValidateCmd() *cobra.Command {\n\tvar (\n\t\tflags migrateValidateFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"validate [flags]\",\n\t\t\tShort: \"Validates the migration directories checksum and SQL statements.\",\n\t\t\tLong: `'atlas migrate validate' computes the integrity hash sum of the migration directory and compares it to the\natlas.sum file. If there is a mismatch it will be reported. If the --dev-url flag is given, the migration\nfiles are executed on the connected database in order to validate SQL semantics.`,\n\t\t\tExample: `  atlas migrate validate\n  atlas migrate validate --dir \"file:///path/to/migration/directory\"\n  atlas migrate validate --dir \"file:///path/to/migration/directory\" --dev-url \"docker://mysql/8/dev\"\n  atlas migrate validate --env dev --dev-url \"docker://postgres/15/dev?search_path=public\"`,\n\t\t\tPreRunE: func(cmd *cobra.Command, _ []string) error {\n\t\t\t\tif err := migrateFlagsFromConfig(cmd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := dirFormatBC(flags.dirFormat, &flags.dirURL); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\terr := checkDir(cmd, flags.dirURL, false)\n\t\t\t\treturn err\n\t\t\t},\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\treturn migrateValidateRun(cmd, args, flags)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagDevURL(cmd.Flags(), &flags.devURL)\n\taddFlagDirURL(cmd.Flags(), &flags.dirURL)\n\taddFlagDirFormat(cmd.Flags(), &flags.dirFormat)\n\treturn cmd\n}\n\nfunc migrateValidateRun(cmd *cobra.Command, _ []string, flags migrateValidateFlags) error {\n\t// Validating the integrity is done by the PersistentPreRun already.\n\tif flags.devURL == \"\" {\n\t\t// If there is no --dev-url given do not attempt to replay the migration directory.\n\t\treturn nil\n\t}\n\t// Open a client for the dev-db.\n\tdev, err := sqlclient.Open(cmd.Context(), flags.devURL)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer dev.Close()\n\t// Currently, only our own migration file format is supported.\n\tdir, err := cmdmigrate.Dir(cmd.Context(), flags.dirURL, false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tex, err := migrate.NewExecutor(dev.Driver, dir, migrate.NopRevisionReadWriter{})\n\tif err != nil {\n\t\treturn err\n\t}\n\tif _, err := ex.Replay(cmd.Context(), func() migrate.StateReader {\n\t\tif dev.URL.Schema != \"\" {\n\t\t\treturn migrate.SchemaConn(dev, \"\", nil)\n\t\t}\n\t\treturn migrate.RealmConn(dev, nil)\n\t}()); err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {\n\t\treturn fmt.Errorf(\"replaying the migration directory: %w\", err)\n\t}\n\treturn nil\n}\n\nconst applyLockValue = \"atlas_migrate_execute\"\n\nfunc checkRevisionSchemaClarity(cmd *cobra.Command, c *sqlclient.Client, revisionSchemaFlag string) error {\n\t// The \"old\" default  behavior for the revision schema location was to store the revision table in its own schema.\n\t// Now, the table is saved in the connected schema, if any. To keep the backwards compatability, we now require\n\t// for schema bound connections to have the schema-revision flag present if there is no revision table in the schema\n\t// but the old default schema does have one.\n\tif c.URL.Schema != \"\" && revisionSchemaFlag == \"\" {\n\t\t// If the schema does not contain a revision table, but we can find a table in the previous default schema,\n\t\t// abort and tell the user to specify the intention.\n\t\topts := &schema.InspectOptions{Tables: []string{revision.Table}, Mode: schema.InspectTables}\n\t\ts, err := c.InspectSchema(cmd.Context(), \"\", opts)\n\t\tvar ok bool\n\t\tswitch {\n\t\tcase schema.IsNotExistError(err):\n\t\t\t// If the schema does not exist, the table does not as well.\n\t\tcase err != nil:\n\t\t\treturn err\n\t\tdefault:\n\t\t\t// Connected schema does exist, check if the table does.\n\t\t\t_, ok = s.Table(revision.Table)\n\t\t}\n\t\tif !ok { // Either schema or table does not exist.\n\t\t\t// Check for the old default schema. If it does not exist, we have no problem.\n\t\t\ts, err := c.InspectSchema(cmd.Context(), defaultRevisionSchema, opts)\n\t\t\tswitch {\n\t\t\tcase schema.IsNotExistError(err):\n\t\t\t\t// Schema does not exist, we can proceed.\n\t\t\tcase err != nil:\n\t\t\t\treturn err\n\t\t\tdefault:\n\t\t\t\tif _, ok := s.Table(revision.Table); ok {\n\t\t\t\t\tfmt.Fprintf(cmd.OutOrStderr(),\n\t\t\t\t\t\t`We couldn't find a revision table in the connected schema but found one in \nthe schema 'atlas_schema_revisions' and cannot determine the desired behavior.\n\nAs a safety guard, we require you to specify whether to use the existing\ntable in 'atlas_schema_revisions' or create a new one in the connected schema\nby providing the '--revisions-schema' flag or deleting the 'atlas_schema_revisions'\nschema if it is unused.\n\n`)\n\t\t\t\t\tcmd.SilenceUsage = true\n\t\t\t\t\tcmd.SilenceErrors = true\n\t\t\t\t\treturn errors.New(\"ambiguous revision table\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc entRevisions(ctx context.Context, c *sqlclient.Client, flag string) (cmdmigrate.RevisionReadWriter, error) {\n\treturn cmdmigrate.RevisionsForClient(ctx, c, revisionSchemaName(c, flag))\n}\n\n// defaultRevisionSchema is the default schema for storing revisions table.\nconst defaultRevisionSchema = \"atlas_schema_revisions\"\n\nfunc revisionSchemaName(c *sqlclient.Client, flag string) string {\n\tswitch {\n\tcase flag != \"\":\n\t\treturn flag\n\tcase c.URL.Schema != \"\":\n\t\treturn c.URL.Schema\n\tdefault:\n\t\treturn defaultRevisionSchema\n\t}\n}\n\nconst (\n\ttxModeNone      = \"none\"\n\ttxModeAll       = \"all\"\n\ttxModeFile      = \"file\"\n\ttxModeDirective = \"txmode\"\n\n\texecOrderLinear     = \"linear\"\n\texecOrderLinearSkip = \"linear-skip\"\n\texecOrderNonLinear  = \"non-linear\"\n)\n\n// tx handles wrapping migration execution in transactions.\ntype tx struct {\n\tdryRun       bool\n\tmode, schema string\n\tc            *sqlclient.Client\n\trrw          migrate.RevisionReadWriter\n\t// current transaction context.\n\ttx    *sqlclient.TxClient\n\ttxrrw migrate.RevisionReadWriter\n}\n\n// driverFor returns the migrate.Driver to use to execute migration statements.\nfunc (tx *tx) driverFor(ctx context.Context, f migrate.File) (migrate.Driver, migrate.RevisionReadWriter, error) {\n\tif tx.dryRun {\n\t\t// If the --dry-run flag is given we don't want to execute any statements on the database.\n\t\treturn &dryRunDriver{tx.c.Driver}, &dryRunRevisions{tx.rrw}, nil\n\t}\n\tmode, err := tx.modeFor(f)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tswitch mode {\n\tcase txModeNone:\n\t\treturn tx.c.Driver, tx.rrw, nil\n\tcase txModeFile:\n\t\t// In file-mode, this function is called each time a new file is executed. Open a transaction.\n\t\tif tx.tx != nil {\n\t\t\treturn nil, nil, errors.New(\"unexpected active transaction\")\n\t\t}\n\t\tvar err error\n\t\ttx.tx, err = tx.c.Tx(ctx, nil)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tif tx.txrrw, err = entRevisions(ctx, tx.tx.Client, tx.schema); err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\treturn tx.tx.Driver, tx.txrrw, nil\n\tcase txModeAll:\n\t\t// In file-mode, this function is called each time a new file is executed. Since we wrap all files into one\n\t\t// huge transaction, if there already is an opened one, use that.\n\t\tif tx.tx == nil {\n\t\t\tvar err error\n\t\t\ttx.tx, err = tx.c.Tx(ctx, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\t\t\tif tx.txrrw, err = entRevisions(ctx, tx.tx.Client, tx.schema); err != nil {\n\t\t\t\treturn nil, nil, err\n\t\t\t}\n\t\t}\n\t\treturn tx.tx.Driver, tx.txrrw, nil\n\tdefault:\n\t\treturn nil, nil, fmt.Errorf(\"unknown tx-mode %q\", mode)\n\t}\n}\n\n// mayRollback may roll back a transaction depending on the given transaction mode.\nfunc (tx *tx) mayRollback(err error) error {\n\tif tx.tx != nil && err != nil {\n\t\tif err2 := tx.tx.Rollback(); err2 != nil {\n\t\t\terr = fmt.Errorf(\"%v: %w\", err2, err)\n\t\t}\n\t}\n\treturn err\n}\n\n// mayCommit may commit a transaction depending on the given transaction mode.\nfunc (tx *tx) mayCommit() error {\n\t// Only commit if each file is wrapped in a transaction.\n\tif tx.tx != nil && !tx.dryRun && tx.mode == txModeFile {\n\t\treturn tx.commit()\n\t}\n\treturn nil\n}\n\n// commit the transaction, if one is active.\nfunc (tx *tx) commit() error {\n\tif tx.tx == nil {\n\t\treturn nil\n\t}\n\tdefer func() { tx.tx, tx.txrrw = nil, nil }()\n\treturn tx.tx.Commit()\n}\n\nfunc (tx *tx) modeFor(f migrate.File) (string, error) {\n\tl, ok := f.(*migrate.LocalFile)\n\tif !ok {\n\t\treturn tx.mode, nil\n\t}\n\tswitch m, err := txmodeFor(l); {\n\tcase err != nil:\n\t\treturn \"\", err\n\tcase m == \"\", m == tx.mode:\n\t\treturn tx.mode, nil\n\tdefault: // m == txModeNone, m == txModeFile\n\t\tif tx.mode == txModeAll {\n\t\t\treturn \"\", fmt.Errorf(\"cannot set txmode directive to %q in %q when txmode %q is set globally\", m, l.Name(), txModeAll)\n\t\t}\n\t\treturn m, nil\n\t}\n}\n\n// txmodeFor returns the transaction mode for the given file.\nfunc txmodeFor(f *migrate.LocalFile) (string, error) {\n\tswitch ds := f.Directive(txModeDirective); {\n\tcase len(ds) == 0:\n\t\treturn \"\", nil\n\tcase len(ds) > 1:\n\t\treturn \"\", fmt.Errorf(\"multiple txmode values found in file %q: %q\", f.Name(), ds)\n\tcase ds[0] == txModeAll:\n\t\treturn \"\", fmt.Errorf(\"txmode %q is not allowed in file directive %q. Use %q instead\", txModeAll, f.Name(), txModeFile)\n\tcase ds[0] == txModeNone, ds[0] == txModeFile:\n\t\treturn ds[0], nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unknown txmode %q found in file directive %q\", ds[0], f.Name())\n\t}\n}\n\nfunc operatorVersion() string {\n\tv, _ := parseV(version)\n\treturn \"Atlas CLI \" + v\n}\n\n// dirFormatBC ensures the soon-to-be deprecated --dir-format flag gets set on all migration directory URLs.\nfunc dirFormatBC(flag string, urls ...*string) error {\n\tfor _, s := range urls {\n\t\tu, err := url.Parse(*s)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !u.Query().Has(\"format\") && flag != \"\" {\n\t\t\tq := u.Query()\n\t\t\tq.Set(\"format\", flag)\n\t\t\tu.RawQuery = q.Encode()\n\t\t\t*s = u.String()\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc checkDir(cmd *cobra.Command, url string, create bool) error {\n\td, err := cmdmigrate.Dir(cmd.Context(), url, create)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err = migrate.Validate(d); err != nil {\n\t\tprintChecksumError(cmd, err)\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc printChecksumError(cmd *cobra.Command, err error) {\n\tcmd.SilenceUsage = true\n\tout := cmd.OutOrStderr()\n\tfmt.Fprintln(out, \"You have a checksum error in your migration directory.\")\n\tif csErr := (&migrate.ChecksumError{}); errors.As(err, &csErr) {\n\t\tfmt.Fprintf(out, \"\\n\\tL%d: %s was %s\\n\\n\", csErr.Line, csErr.File, csErr.Reason)\n\t}\n\tfmt.Fprintf(\n\t\tout,\n\t\t\"Please check your migration files and run %v to re-hash the contents\\n\\n\",\n\t\tcmdlog.ColorCyan(\"'atlas migrate hash'\"),\n\t)\n}\n\n// selectScheme validates the scheme of the provided to urls and returns the selected\n// url scheme. Currently, all URLs must be of the same scheme, and only multiple\n// \"file://\" URLs are allowed.\nfunc selectScheme(urls []string) (string, error) {\n\tvar scheme string\n\tif len(urls) == 0 {\n\t\treturn \"\", errors.New(\"at least one url is required\")\n\t}\n\tfor _, u := range urls {\n\t\tparts := strings.SplitN(u, \"://\", 2)\n\t\tswitch current := parts[0]; {\n\t\tcase len(parts) == 1:\n\t\t\tex := filepath.Ext(u)\n\t\t\tswitch f, err := os.Stat(u); {\n\t\t\tcase err != nil:\n\t\t\tcase f.IsDir(), ex == cmdext.FileTypeSQL, ex == cmdext.FileTypeHCL:\n\t\t\t\treturn \"\", fmt.Errorf(\"missing scheme. Did you mean file://%s?\", u)\n\t\t\t}\n\t\t\treturn \"\", errors.New(\"missing scheme. See: https://atlasgo.io/url\")\n\t\tcase scheme == \"\":\n\t\t\tscheme = current\n\t\tcase scheme != current:\n\t\t\treturn \"\", fmt.Errorf(\"got mixed --to url schemes: %q and %q, the desired state must be provided from a single kind of source\", scheme, current)\n\t\tcase current != cmdext.SchemaTypeFile:\n\t\t\treturn \"\", fmt.Errorf(\"got multiple --to urls of scheme %q, only multiple 'file://' urls are supported\", current)\n\t\t}\n\t}\n\treturn scheme, nil\n}\n\nfunc migrateFlagsFromConfig(cmd *cobra.Command) error {\n\tenv, err := selectEnv(cmd)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn setMigrateEnvFlags(cmd, env)\n}\n\nfunc setMigrateEnvFlags(cmd *cobra.Command, env *Env) error {\n\tif err := maySetFlag(cmd, flagURL, env.URL); err != nil {\n\t\treturn err\n\t}\n\tif err := maySetFlag(cmd, flagDevURL, env.DevURL); err != nil {\n\t\treturn err\n\t}\n\tif err := maySetFlag(cmd, flagDirURL, env.Migration.Dir); err != nil {\n\t\treturn err\n\t}\n\tif err := maySetFlag(cmd, flagDirFormat, env.Migration.Format); err != nil {\n\t\treturn err\n\t}\n\tif err := maySetFlag(cmd, flagBaseline, env.Migration.Baseline); err != nil {\n\t\treturn err\n\t}\n\tif err := maySetFlag(cmd, flagRevisionSchema, env.Migration.RevisionsSchema); err != nil {\n\t\treturn err\n\t}\n\tswitch cmd.Name() {\n\tcase \"apply\":\n\t\tif err := maySetFlag(cmd, flagFormat, env.Format.Migrate.Apply); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagLockTimeout, env.Migration.LockTimeout); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagExecOrder, strings.ReplaceAll(strings.ToLower(env.Migration.ExecOrder), \"_\", \"-\")); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase \"down\":\n\t\tif err := maySetFlag(cmd, flagFormat, env.Format.Migrate.Down); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagLockTimeout, env.Migration.LockTimeout); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase \"diff\", \"checkpoint\":\n\t\tif err := maySetFlag(cmd, flagLockTimeout, env.Migration.LockTimeout); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagFormat, env.Format.Migrate.Diff); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase \"lint\":\n\t\tif err := maySetFlag(cmd, flagFormat, env.Format.Migrate.Lint); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagFormat, env.Lint.Format); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagLatest, strconv.Itoa(env.Lint.Latest)); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagGitDir, env.Lint.Git.Dir); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagGitBase, env.Lint.Git.Base); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase \"status\":\n\t\tif err := maySetFlag(cmd, flagFormat, env.Format.Migrate.Status); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t// Transform \"src\" to a URL.\n\tsrcs, err := env.Sources()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor i, s := range srcs {\n\t\tif isURL(s) {\n\t\t\tcontinue\n\t\t}\n\t\tif s, err = filepath.Abs(s); err != nil {\n\t\t\treturn fmt.Errorf(\"finding abs path to source: %q: %w\", s, err)\n\t\t}\n\t\tsrcs[i] = \"file://\" + s\n\t}\n\tif err := maySetFlag(cmd, flagTo, strings.Join(srcs, \",\")); err != nil {\n\t\treturn err\n\t}\n\tif err := maySetFlag(cmd, flagSchema, strings.Join(env.Schemas, \",\")); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// isURL returns true if the given string\n// is an Atlas URL with a scheme.\nfunc isURL(s string) bool {\n\tu, err := url.Parse(s)\n\treturn err == nil && u.Scheme != \"\"\n}\n\n// cmdEnvsRun executes a given command on each of the configured environment.\nfunc cmdEnvsRun(\n\tenvs []*Env,\n\tsetFlags func(*cobra.Command, *Env) error,\n\tcmd *cobra.Command,\n\trunCmd func(*Env) error,\n) error {\n\tvar (\n\t\tw     bytes.Buffer\n\t\tout   = cmd.OutOrStdout()\n\t\treset = resetFromEnv(cmd)\n\t)\n\tcmd.SetOut(io.MultiWriter(out, &w))\n\tdefer cmd.SetOut(out)\n\tfor i, e := range envs {\n\t\tif err := setFlags(cmd, e); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := runCmd(e); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tb := bytes.TrimLeft(w.Bytes(), \" \\t\\r\")\n\t\t// In case a custom logging was configured, ensure there is\n\t\t// a newline separator between the different environments.\n\t\tif cmd.Flags().Changed(flagFormat) && bytes.LastIndexByte(b, '\\n') != len(b)-1 && i != len(envs)-1 {\n\t\t\tcmd.Println()\n\t\t}\n\t\treset()\n\t\tw.Reset()\n\t}\n\treturn nil\n}\n\ntype editDir struct{ *migrate.LocalDir }\n\n// WriteFile implements the migrate.Dir.WriteFile method.\nfunc (d *editDir) WriteFile(name string, b []byte) (err error) {\n\tif name != migrate.HashFileName {\n\t\tif b, err = edit(name, b); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn d.LocalDir.WriteFile(name, b)\n}\n\n// edit allows editing the file content using editor.\nfunc edit(name string, src []byte) ([]byte, error) {\n\tp := filepath.Join(os.TempDir(), name)\n\tif err := os.WriteFile(p, src, 0644); err != nil {\n\t\treturn nil, fmt.Errorf(\"write source content to temp file: %w\", err)\n\t}\n\tdefer os.Remove(p)\n\teditor := \"vi\"\n\tif e := os.Getenv(\"EDITOR\"); e != \"\" {\n\t\teditor = e\n\t}\n\tcmd := exec.Command(\"sh\", \"-c\", editor+\" \"+p)\n\tcmd.Stdin = os.Stdin\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\tif err := cmd.Run(); err != nil {\n\t\treturn nil, fmt.Errorf(\"exec edit: %w\", err)\n\t}\n\tb, err := os.ReadFile(p)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read edited temp file: %w\", err)\n\t}\n\treturn b, nil\n}\n\ntype (\n\t// dryRunDriver wraps a migrate.Driver without executing any SQL statements.\n\tdryRunDriver struct{ migrate.Driver }\n\n\t// dryRunRevisions wraps a migrate.RevisionReadWriter without executing any SQL statements.\n\tdryRunRevisions struct{ migrate.RevisionReadWriter }\n)\n\n// ExecContext overrides the wrapped schema.ExecQuerier to not execute any SQL.\nfunc (dryRunDriver) ExecContext(context.Context, string, ...any) (sql.Result, error) {\n\treturn nil, nil\n}\n\n// Lock implements the schema.Locker interface.\nfunc (dryRunDriver) Lock(context.Context, string, time.Duration) (schema.UnlockFunc, error) {\n\t// We dry-run, we don't execute anything. Locking is not required.\n\treturn func() error { return nil }, nil\n}\n\n// CheckClean implements the migrate.CleanChecker interface.\nfunc (dryRunDriver) CheckClean(context.Context, *migrate.TableIdent) error {\n\treturn nil\n}\n\n// Snapshot implements the migrate.Snapshoter interface.\nfunc (dryRunDriver) Snapshot(context.Context) (migrate.RestoreFunc, error) {\n\t// We dry-run, we don't execute anything. Snapshotting not required.\n\treturn func(context.Context) error { return nil }, nil\n}\n\n// WriteRevision overrides the wrapped migrate.RevisionReadWriter to not saved any changes to revisions.\nfunc (dryRunRevisions) WriteRevision(context.Context, *migrate.Revision) error {\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/migrate_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage cmdapi\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strconv\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdlog\"\n\tcmdmigrate \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"github.com/spf13/cobra\"\n)\n\n// migrateApplyRun represents the 'atlas migrate apply' subcommand.\nfunc migrateApplyRun(cmd *cobra.Command, args []string, flags migrateApplyFlags, env *Env, mr *MigrateReport) (err error) {\n\tvar (\n\t\tcount int\n\t\tctx   = cmd.Context()\n\t)\n\tif len(args) > 0 {\n\t\tif count, err = strconv.Atoi(args[0]); err != nil {\n\t\t\tif nerr := (&strconv.NumError{}); errors.As(err, &nerr) && nerr.Err != nil {\n\t\t\t\terr = nerr.Err\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"invalid amount argument %q (%w). Omit the argument or pass a valid integer instead\", args[0], err)\n\t\t}\n\t\tif count < 1 {\n\t\t\treturn fmt.Errorf(\"cannot apply '%d' migration files\", count)\n\t\t}\n\t}\n\tdirURL, err := url.Parse(flags.dirURL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse dir-url: %w\", err)\n\t}\n\t// Open and validate the migration directory.\n\tdir, err := cmdmigrate.DirURL(ctx, dirURL, false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := migrate.Validate(dir); err != nil {\n\t\tprintChecksumError(cmd, err)\n\t\treturn err\n\t}\n\t// Open a client to the database.\n\tif flags.url == \"\" {\n\t\treturn errors.New(`required flag \"url\" not set`)\n\t}\n\tclient, err := env.openClient(ctx, flags.url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer client.Close()\n\t// Prevent usage printing after input validation.\n\tcmd.SilenceUsage = true\n\t// Acquire a lock.\n\tunlock, err := client.Driver.Lock(ctx, applyLockValue, flags.lockTimeout)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"acquiring database lock: %w\", err)\n\t}\n\t// If unlocking fails notify the user about it.\n\tdefer func() { cobra.CheckErr(unlock()) }()\n\tif err := checkRevisionSchemaClarity(cmd, client, flags.revisionSchema); err != nil {\n\t\treturn err\n\t}\n\tvar rrw migrate.RevisionReadWriter\n\tif rrw, err = entRevisions(ctx, client, flags.revisionSchema); err != nil {\n\t\treturn err\n\t}\n\tmrrw, ok := rrw.(cmdmigrate.RevisionReadWriter)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected revision read-writer type: %T\", rrw)\n\t}\n\tif err := mrrw.Migrate(ctx); err != nil {\n\t\treturn err\n\t}\n\t// Setup reporting info.\n\treport := cmdlog.NewMigrateApply(ctx, client, dirURL)\n\tmr.Init(client, report, mrrw)\n\t// If cloud reporting is enabled, and we cannot obtain the current\n\t// target identifier, abort and report it to the user.\n\tif err := mr.RecordTargetID(cmd.Context()); err != nil {\n\t\treturn err\n\t}\n\t// Determine pending files.\n\topts, err := flags.migrateOptions()\n\tif err != nil {\n\t\treturn err\n\t}\n\topts = append(opts, migrate.WithOperatorVersion(operatorVersion()), migrate.WithLogger(report))\n\tex, err := migrate.NewExecutor(client.Driver, dir, rrw, opts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tpending, err := ex.Pending(ctx)\n\tif err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {\n\t\tmr.RecordPlanError(cmd, flags, err.Error())\n\t\treturn err\n\t}\n\tnoPending := errors.Is(err, migrate.ErrNoPendingFiles)\n\t// Get the pending files before obtaining applied revisions,\n\t// as the Executor may write a baseline revision in the table.\n\tapplied, err := rrw.ReadRevisions(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif noPending {\n\t\tmigrate.LogNoPendingFiles(report, applied)\n\t\treturn mr.Done(cmd, flags)\n\t}\n\tif l := len(pending); count == 0 || count >= l {\n\t\t// Cannot apply more than len(pending) migration files.\n\t\tcount = l\n\t}\n\tpending = pending[:count]\n\tmigrate.LogIntro(report, applied, pending)\n\tvar (\n\t\tmux = tx{\n\t\t\tdryRun: flags.dryRun,\n\t\t\tmode:   flags.txMode,\n\t\t\tschema: flags.revisionSchema,\n\t\t\tc:      client,\n\t\t\trrw:    rrw,\n\t\t}\n\t\tdrv migrate.Driver\n\t)\n\tfor _, f := range pending {\n\t\tif drv, rrw, err = mux.driverFor(ctx, f); err != nil {\n\t\t\tbreak\n\t\t}\n\t\tif ex, err = migrate.NewExecutor(drv, dir, rrw, opts...); err != nil {\n\t\t\treturn fmt.Errorf(\"unexpected executor creation error: %w\", err)\n\t\t}\n\t\tif err = mux.mayRollback(ex.Execute(ctx, f)); err != nil {\n\t\t\tbreak\n\t\t}\n\t\tif err = mux.mayCommit(); err != nil {\n\t\t\tbreak\n\t\t}\n\t}\n\tif err == nil {\n\t\tif err = mux.commit(); err == nil {\n\t\t\treport.Log(migrate.LogDone{})\n\t\t}\n\t}\n\tif err != nil {\n\t\treport.Error = err.Error()\n\t}\n\treturn errors.Join(err, mr.Done(cmd, flags))\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/migrate_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdapi\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdlog\"\n\tmigrate2 \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t\"ariga.io/atlas/sql/sqlite\"\n\t_ \"ariga.io/atlas/sql/sqlite\"\n\t_ \"ariga.io/atlas/sql/sqlite/sqlitecheck\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/google/uuid\"\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestMigrate(t *testing.T) {\n\t_, err := runCmd(migrateCmd())\n\trequire.NoError(t, err)\n}\n\nfunc TestMigrate_Import(t *testing.T) {\n\tfor _, tool := range []string{\"dbmate\", \"flyway\", \"golang-migrate\", \"goose\", \"liquibase\"} {\n\t\tp := t.TempDir()\n\t\tt.Run(tool, func(t *testing.T) { // remove this once --dir-format is removed. Test is kept to ensure BC.\n\t\t\tpath := filepath.FromSlash(\"testdata/import/\" + tool)\n\t\t\tout, err := runCmd(\n\t\t\t\tmigrateImportCmd(),\n\t\t\t\t\"--from\", \"file://\"+path,\n\t\t\t\t\"--to\", \"file://\"+p,\n\t\t\t\t\"--dir-format\", tool,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Zero(t, out)\n\n\t\t\tpath += \"_gold\"\n\t\t\tex, err := os.ReadDir(path)\n\t\t\trequire.NoError(t, err)\n\t\t\tac, err := os.ReadDir(p)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, len(ex)+1, len(ac)) // sum file\n\n\t\t\tfor i := range ex {\n\t\t\t\te, err := os.ReadFile(filepath.Join(path, ex[i].Name()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\ta, err := os.ReadFile(filepath.Join(p, ex[i].Name()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, string(e), string(a))\n\t\t\t}\n\t\t})\n\t\tp = t.TempDir()\n\t\tt.Run(tool, func(t *testing.T) {\n\t\t\tpath := filepath.FromSlash(\"testdata/import/\" + tool)\n\t\t\tout, err := runCmd(\n\t\t\t\tmigrateImportCmd(),\n\t\t\t\t\"--from\", fmt.Sprintf(\"file://%s?format=%s\", path, tool),\n\t\t\t\t\"--to\", \"file://\"+p,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Zero(t, out)\n\n\t\t\tpath += \"_gold\"\n\t\t\tex, err := os.ReadDir(path)\n\t\t\trequire.NoError(t, err)\n\t\t\tac, err := os.ReadDir(p)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, len(ex)+1, len(ac)) // sum file\n\n\t\t\tfor i := range ex {\n\t\t\t\te, err := os.ReadFile(filepath.Join(path, ex[i].Name()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\ta, err := os.ReadFile(filepath.Join(p, ex[i].Name()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, string(e), string(a))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestMigrate_Apply(t *testing.T) {\n\tvar (\n\t\tp   = t.TempDir()\n\t\tctx = context.Background()\n\t)\n\t// Disable text coloring in testing\n\t// to assert on string matching.\n\tcolor.NoColor = true\n\n\t// Fails on empty directory.\n\ts, err := runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://\"+p,\n\t\t\"-u\", openSQLite(t, \"\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"No migration files to execute\\n\", s)\n\n\t// Fails on directory without sum file.\n\trequire.NoError(t, os.Rename(\n\t\tfilepath.FromSlash(\"testdata/sqlite/atlas.sum\"),\n\t\tfilepath.FromSlash(\"testdata/sqlite/atlas.sum.bak\"),\n\t))\n\tt.Cleanup(func() {\n\t\tos.Rename(filepath.FromSlash(\"testdata/sqlite/atlas.sum.bak\"), filepath.FromSlash(\"testdata/sqlite/atlas.sum\"))\n\t})\n\n\t_, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite\",\n\t\t\"--url\", openSQLite(t, \"\"),\n\t)\n\trequire.ErrorIs(t, err, migrate.ErrChecksumNotFound)\n\trequire.NoError(t, os.Rename(\n\t\tfilepath.FromSlash(\"testdata/sqlite/atlas.sum.bak\"),\n\t\tfilepath.FromSlash(\"testdata/sqlite/atlas.sum\"),\n\t))\n\n\t// A lock will prevent execution.\n\tsqlclient.Register(\n\t\t\"sqlitelockapply\",\n\t\tsqlclient.OpenerFunc(func(ctx context.Context, u *url.URL) (*sqlclient.Client, error) {\n\t\t\tclient, err := sqlclient.Open(ctx, strings.Replace(u.String(), u.Scheme, \"sqlite\", 1))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tclient.Driver = &sqliteLockerDriver{client.Driver}\n\t\t\treturn client, nil\n\t\t}),\n\t\tsqlclient.RegisterDriverOpener(func(db schema.ExecQuerier) (migrate.Driver, error) {\n\t\t\tdrv, err := sqlite.Open(db)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn &sqliteLockerDriver{drv}, nil\n\t\t}),\n\t)\n\tf, err := os.Create(filepath.Join(p, \"test.db\"))\n\trequire.NoError(t, err)\n\trequire.NoError(t, f.Close())\n\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite\",\n\t\t\"--url\", fmt.Sprintf(\"sqlitelockapply://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test.db\")),\n\t)\n\trequire.ErrorIs(t, err, errLock)\n\trequire.True(t, strings.HasPrefix(s, \"Error: acquiring database lock: \"+errLock.Error()))\n\n\t// Apply zero throws error.\n\tfor _, n := range []string{\"-1\", \"0\"} {\n\t\t_, err = runCmd(\n\t\t\tmigrateApplyCmd(),\n\t\t\t\"--dir\", \"file://testdata/sqlite\",\n\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test.db\")),\n\t\t\t\"--\", n,\n\t\t)\n\t\trequire.EqualError(t, err, fmt.Sprintf(\"cannot apply '%s' migration files\", n))\n\t}\n\n\t// Will work and print stuff to the console.\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test.db\")),\n\t\t\"1\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Contains(t, s, \"20220318104614\")                           // log to version\n\trequire.Contains(t, s, \"CREATE TABLE tbl (`col` int NOT NULL);\")   // logs statement\n\trequire.NotContains(t, s, \"ALTER TABLE `tbl` ADD `col_2` bigint;\") // does not execute second file\n\trequire.Contains(t, s, \"1 migration\")                              // logs amount of migrations\n\trequire.Contains(t, s, \"1 sql statement\")\n\n\t// Transactions will be wrapped per file. If the second file has an error, first still is applied.\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite2\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test2.db\")),\n\t)\n\trequire.Error(t, err)\n\trequire.Contains(t, s, \"20220318104614\")                           // log to version\n\trequire.Contains(t, s, \"CREATE TABLE tbl (`col` int NOT NULL);\")   // logs statement\n\trequire.Contains(t, s, \"ALTER TABLE `tbl` ADD `col_2` bigint;\")    // does execute first stmt first second file\n\trequire.Contains(t, s, \"ALTER TABLE `tbl` ADD `col_3` bigint;\")    // does execute second stmt first second file\n\trequire.NotContains(t, s, \"ALTER TABLE `tbl` ADD `col_4` bigint;\") // but not third\n\trequire.Contains(t, s, \"-- 1 migration ok, 1 with errors\")         // logs amount of migrations\n\trequire.Contains(t, s, \"-- 2 sql statements ok, 1 with errors\")    // logs amount of statement\n\trequire.Contains(t, s, \"near \\\"asdasd\\\": syntax error\")            // logs error summary\n\n\tc, err := sqlclient.Open(ctx, fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test2.db\")))\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, c.Close())\n\t})\n\tsch, err := c.InspectSchema(ctx, \"\", nil)\n\ttbl, ok := sch.Table(\"tbl\")\n\trequire.True(t, ok)\n\t_, ok = tbl.Column(\"col_2\")\n\trequire.False(t, ok)\n\t_, ok = tbl.Column(\"col_3\")\n\trequire.False(t, ok)\n\trrw, err := migrate2.NewEntRevisions(ctx, c)\n\trequire.NoError(t, err)\n\trevs, err := rrw.ReadRevisions(ctx)\n\trequire.NoError(t, err)\n\trequire.Len(t, revs, 1)\n\n\t// Running again will pick up the failed statement and try it again.\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite2\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test2.db\")),\n\t)\n\trequire.Error(t, err)\n\trequire.Contains(t, s, \"20220318104614\")                            // currently applied version\n\trequire.Contains(t, s, \"20220318104615\")                            // retry second (partially applied)\n\trequire.NotContains(t, s, \"CREATE TABLE tbl (`col` int NOT NULL);\") // will not attempt stmts from first file\n\trequire.Contains(t, s, \"ALTER TABLE `tbl` ADD `col_2` bigint;\")     // picks up first statement\n\trequire.Contains(t, s, \"ALTER TABLE `tbl` ADD `col_3` bigint;\")     // does execute second stmt first second file\n\trequire.NotContains(t, s, \"ALTER TABLE `tbl` ADD `col_4` bigint;\")  // but not third\n\trequire.Contains(t, s, \"-- 1 migration with errors\")                // logs amount of migrations\n\trequire.Contains(t, s, \"-- 1 sql statement ok, 1 with errors\")      // logs amount of statement\n\trequire.Contains(t, s, \"near \\\"asdasd\\\": syntax error\")             // logs error summary\n\n\t// Editing an applied line will raise error.\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite2\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test2.db\")),\n\t\t\"--tx-mode\", \"none\",\n\t)\n\tt.Cleanup(func() {\n\t\t_ = os.RemoveAll(\"testdata/sqlite3\")\n\t})\n\trequire.NoError(t, exec.Command(\"cp\", \"-r\", \"testdata/sqlite2\", \"testdata/sqlite3\").Run())\n\tsed(t, \"s/col_2/col_5/g\", \"testdata/sqlite3/20220318104615_second.sql\")\n\t_, err = runCmd(migrateHashCmd(), \"--dir\", \"file://testdata/sqlite3\")\n\trequire.NoError(t, err)\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite3\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test2.db\")),\n\t)\n\trequire.ErrorAs(t, err, &migrate.HistoryChangedError{})\n\n\t// Fixing the migration file will finish without errors.\n\tsed(t, \"s/col_5/col_2/g\", \"testdata/sqlite3/20220318104615_second.sql\")\n\tsed(t, \"s/asdasd //g\", \"testdata/sqlite3/20220318104615_second.sql\")\n\t_, err = runCmd(migrateHashCmd(), \"--dir\", \"file://testdata/sqlite3\")\n\trequire.NoError(t, err)\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite3\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test2.db\")),\n\t)\n\trequire.NoError(t, err)\n\trequire.Contains(t, s, \"20220318104615\")                        // retry second (partially applied)\n\trequire.Contains(t, s, \"ALTER TABLE `tbl` ADD `col_3` bigint;\") // does execute second stmt first second file\n\trequire.Contains(t, s, \"ALTER TABLE `tbl` ADD `col_4` bigint;\") // does execute second stmt first second file\n\trequire.Contains(t, s, \"1 migrations\")                          // logs amount of migrations\n\trequire.Contains(t, s, \"2\")                                     // logs amount of statement\n\trequire.NotContains(t, s, \"Error: Execution had errors:\")       // logs error summary\n\trequire.NotContains(t, s, \"near \\\"asdasd\\\": syntax error\")      // logs error summary\n\n\t// Running again will report database being in clean state.\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite3\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test2.db\")),\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"No migration files to execute\\n\", s)\n\n\t// Dry run will print the statements in second migration file without executing them.\n\t// No changes to the revisions will be done.\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test.db\")),\n\t\t\"--dry-run\",\n\t\t\"1\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Contains(t, s, \"20220318104615\")                        // log to version\n\trequire.Contains(t, s, \"ALTER TABLE `tbl` ADD `col_2` bigint;\") // logs statement\n\tc1, err := sqlclient.Open(ctx, fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test.db\")))\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, c1.Close())\n\t})\n\tsch, err = c1.InspectSchema(ctx, \"\", nil)\n\ttbl, ok = sch.Table(\"tbl\")\n\trequire.True(t, ok)\n\t_, ok = tbl.Column(\"col_2\")\n\trequire.False(t, ok)\n\trrw, err = migrate2.NewEntRevisions(ctx, c1)\n\trequire.NoError(t, err)\n\trevs, err = rrw.ReadRevisions(ctx)\n\trequire.NoError(t, err)\n\trequire.Len(t, revs, 1)\n\n\t// Prerequisites for testing missing migration behavior.\n\tc1, err = sqlclient.Open(ctx, fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test3.db\")))\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, c1.Close())\n\t})\n\trequire.NoError(t, os.Rename(\n\t\t\"testdata/sqlite3/20220318104615_second.sql\",\n\t\t\"testdata/sqlite3/20220318104616_second.sql\",\n\t))\n\t_, err = runCmd(migrateHashCmd(), \"--dir\", \"file://testdata/sqlite3\")\n\trequire.NoError(t, err)\n\trrw, err = migrate2.NewEntRevisions(ctx, c1)\n\trequire.NoError(t, err)\n\trequire.NoError(t, rrw.Migrate(ctx))\n\n\t// No changes if the last revision has a greater version than the last migration.\n\trequire.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: \"zzz\"}))\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite3\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test3.db\")),\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"No migration files to execute\\n\", s)\n\n\t// If the revision is before the last but after the first migration, only the last one is pending.\n\t_, err = c1.ExecContext(ctx, \"DROP table `atlas_schema_revisions`\")\n\trequire.NoError(t, err)\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(), \"1\",\n\t\t\"--dir\", \"file://testdata/sqlite3\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test3.db\")),\n\t)\n\trequire.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: \"20220318104615\"}))\n\trequire.NoError(t, err)\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite3\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test3.db\")),\n\t)\n\trequire.NoError(t, err)\n\trequire.NotContains(t, s, \"20220318104614\")                     // log to version\n\trequire.Contains(t, s, \"20220318104616\")                        // log to version\n\trequire.Contains(t, s, \"ALTER TABLE `tbl` ADD `col_2` bigint;\") // logs statement\n\n\t// If the revision is before every migration file, every file is pending.\n\t_, err = c1.ExecContext(ctx, \"DROP table `atlas_schema_revisions`; DROP table `tbl`;\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, rrw.Migrate(ctx))\n\trequire.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: \"1\"}))\n\trequire.NoError(t, err)\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite3\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test3.db\")),\n\t)\n\trequire.NoError(t, err)\n\trequire.Contains(t, s, \"20220318104614\")                         // log to version\n\trequire.Contains(t, s, \"20220318104616\")                         // log to version\n\trequire.Contains(t, s, \"CREATE TABLE tbl (`col` int NOT NULL);\") // logs statement\n\trequire.Contains(t, s, \"ALTER TABLE `tbl` ADD `col_2` bigint;\")  // logs statement\n\n\t// If the revision is partially applied, error out.\n\trequire.NoError(t, rrw.WriteRevision(ctx, &migrate.Revision{Version: \"z\", Description: \"z\", Total: 1}))\n\trequire.NoError(t, err)\n\t_, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite3\",\n\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test3.db\")),\n\t)\n\trequire.EqualError(t, err, migrate.MissingMigrationError{Version: \"z\", Description: \"z\"}.Error())\n}\n\nfunc TestMigrate_ApplyMultiEnv(t *testing.T) {\n\tt.Run(\"FromVars\", func(t *testing.T) {\n\t\tp := t.TempDir()\n\t\th := `\nvariable \"urls\" {\n  type = list(string)\n}\n\nenv \"local\" {\n  for_each = toset(var.urls)\n  url = each.value\n  dev = \"sqlite://ci?mode=memory&cache=shared&_fk=1\"\n  migration {\n    dir = \"file://testdata/sqlite\"\n  }\n}\n`\n\t\tpath := filepath.Join(p, \"atlas.hcl\")\n\t\terr := os.WriteFile(path, []byte(h), 0600)\n\t\trequire.NoError(t, err)\n\t\tcmd := migrateCmd()\n\t\tcmd.AddCommand(migrateApplyCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-c\", \"file://\"+path,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", fmt.Sprintf(\"urls=sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test1.db\")),\n\t\t\t\"--var\", fmt.Sprintf(\"urls=sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test2.db\")),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 2, strings.Count(s, \"Migrating to version 20220318104615 (2 migrations in total)\"), \"execution per environment\")\n\t\t_, err = os.Stat(filepath.Join(p, \"test1.db\"))\n\t\trequire.NoError(t, err)\n\t\t_, err = os.Stat(filepath.Join(p, \"test2.db\"))\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"FromDataSrc\", func(t *testing.T) {\n\t\tvar (\n\t\t\th = `\nvariable \"url\" {\n  type = string\n}\n\nlocals {\n  string = \"%test\"\n  bool   = true\n  int    = 1\n}\n\ndata \"sql\" \"tenants\" {\n  url   = var.url\n  query = <<EOS\nSELECT name FROM tenants\n\tWHERE mode LIKE ? AND active = ? AND created = ?\nEOS\n  # Pass all types of arguments.\n  args  = [local.string, local.bool, local.int]\n}\n\nenv \"local\" {\n  for_each = toset(data.sql.tenants.values)\n  url = \"sqlite://file:${each.value}?cache=shared&_fk=1\"\n  dev = \"sqlite://ci?mode=memory&cache=shared&_fk=1\"\n  migration {\n    dir = \"file://testdata/sqlite\"\n  }\n  log {\n    migrate {\n      apply = format(\n        \"{{ json . | json_merge %q }}\",\n        jsonencode({\n          Tenant: each.value\n        })\n      )\n    }\n  }\n}\n`\n\t\t\tp    = t.TempDir()\n\t\t\tpath = filepath.Join(p, \"atlas.hcl\")\n\t\t\tdbs  = []string{filepath.Join(p, \"test1.db\"), filepath.Join(p, \"test2.db\"), filepath.Join(p, \"test3.db\")}\n\t\t)\n\t\terr := os.WriteFile(path, []byte(h), 0600)\n\t\trequire.NoError(t, err)\n\t\tdb, err := sql.Open(\"sqlite3\", fmt.Sprintf(\"file:%s?cache=shared&_fk=1\", filepath.Join(p, \"tenants.db\")))\n\t\trequire.NoError(t, err)\n\t\t_, err = db.Exec(\"CREATE TABLE `tenants` (`name` TEXT, `mode` TEXT DEFAULT 'test', `active` BOOL DEFAULT TRUE, `created` INT DEFAULT 1);\")\n\t\trequire.NoError(t, err)\n\t\t_, err = db.Exec(\"INSERT INTO `tenants` (`name`) VALUES (?), (?), (?)\", dbs[0], dbs[1], dbs[2])\n\t\trequire.NoError(t, err)\n\n\t\tcmd := migrateCmd()\n\t\tcmd.AddCommand(migrateApplyCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-c\", \"file://\"+path,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", fmt.Sprintf(\"url=sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"tenants.db\")),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 3, strings.Count(s, `\"Tenant\"`))\n\t\trequire.Equal(t, 3, strings.Count(s, `\"Applied\":[{\"Applied\":[\"CREATE TABLE tbl`), \"execution per environment\")\n\t\tfor i := range dbs {\n\t\t\t_, err = os.Stat(dbs[i])\n\t\t\trequire.NoError(t, err)\n\t\t}\n\n\t\tcmd = migrateCmd()\n\t\tcmd.AddCommand(migrateApplyCmd())\n\t\ts, err = runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-c\", \"file://\"+path,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", fmt.Sprintf(\"url=sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"tenants.db\")),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\tfor _, s := range strings.Split(s, \"\\n\") {\n\t\t\tvar r struct {\n\t\t\t\tTenant string\n\t\t\t\tcmdlog.MigrateApply\n\t\t\t}\n\t\t\trequire.NoError(t, json.Unmarshal([]byte(s), &r))\n\t\t\trequire.Empty(t, r.Pending)\n\t\t\trequire.Empty(t, r.Applied)\n\t\t\trequire.NotEmpty(t, r.Tenant)\n\t\t\trequire.Equal(t, \"sqlite\", r.Driver)\n\t\t}\n\t\t_, err = db.Exec(\"INSERT INTO `tenants` (`name`) VALUES (NULL)\")\n\t\trequire.NoError(t, err)\n\t\t_, err = runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-c\", \"file://\"+path,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", fmt.Sprintf(\"url=sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"tenants.db\")),\n\t\t\t// Inject fake variable to enforce re-evaluation of the data source (skip cache).\n\t\t\t\"--var\", fmt.Sprintf(\"cache=%s\", uuid.NewString()),\n\t\t)\n\t\t// Rows should represent real and consistent values.\n\t\trequire.EqualError(t, err, \"data.sql.tenants: unsupported row type: <nil>\")\n\n\t\t_, err = db.Exec(\"DELETE FROM `tenants`\")\n\t\trequire.NoError(t, err)\n\t\ts, err = runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-c\", \"file://\"+path,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", fmt.Sprintf(\"url=sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"tenants.db\")),\n\t\t\t// Inject fake variable to enforce re-evaluation of the data source (skip cache).\n\t\t\t\"--var\", fmt.Sprintf(\"cache=%s\", uuid.NewString()),\n\t\t)\n\t\t// Empty list is expanded to zero blocks.\n\t\trequire.EqualError(t, err, `env \"local\" not defined in config file`)\n\t})\n\n\tt.Run(\"TemplateDir\", func(t *testing.T) {\n\t\tvar (\n\t\t\th = `\nvariable \"path\" {\n  type = string\n}\n\ndata \"template_dir\" \"migrations\" {\n  path = var.path\n  vars = {\n    Env = atlas.env\n  }\n}\n\nenv \"dev\" {\n  url = \"sqlite://${atlas.env}?mode=memory&_fk=1\"\n  migration {\n    dir = data.template_dir.migrations.url\n  }\n}\n\nenv \"prod\" {\n  url = \"sqlite://${atlas.env}?mode=memory&_fk=1\"\n  migration {\n    dir = data.template_dir.migrations.url\n  }\n}\n`\n\t\t\tp    = t.TempDir()\n\t\t\tpath = filepath.Join(p, \"atlas.hcl\")\n\t\t)\n\t\terr := os.WriteFile(path, []byte(h), 0600)\n\t\trequire.NoError(t, err)\n\t\tfor _, e := range []string{\"dev\", \"prod\"} {\n\t\t\tcmd := migrateCmd()\n\t\t\tcmd.AddCommand(migrateApplyCmd())\n\t\t\ts, err := runCmd(\n\t\t\t\tcmd, \"apply\",\n\t\t\t\t\"-c\", \"file://\"+path,\n\t\t\t\t\"--env\", e,\n\t\t\t\t\"--var\", \"path=testdata/templatedir\",\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Contains(t, s, \"Migrating to version 2 (2 migrations in total):\")\n\t\t\trequire.Contains(t, s, fmt.Sprintf(\"create table %s1 (c text);\", e))\n\t\t\trequire.Contains(t, s, fmt.Sprintf(\"create table %s2 (c text);\", e))\n\t\t\trequire.Contains(t, s, fmt.Sprintf(\"create table users_%s2 (c text);\", e))\n\t\t}\n\t})\n}\n\nfunc TestMigrate_ApplyTxMode(t *testing.T) {\n\tfor _, mode := range []string{\"none\", \"file\", \"all\"} {\n\t\tt.Run(mode, func(t *testing.T) {\n\t\t\tp := t.TempDir()\n\t\t\t// Apply the first 2 migrations.\n\t\t\ts, err := runCmd(\n\t\t\t\tmigrateApplyCmd(),\n\t\t\t\t\"--dir\", \"file://testdata/sqlitetx\",\n\t\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test.db\")),\n\t\t\t\t\"--tx-mode\", mode,\n\t\t\t\t\"2\",\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, s)\n\t\t\tdb, err := sql.Open(\"sqlite3\", fmt.Sprintf(\"file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test.db\")))\n\t\t\trequire.NoError(t, err)\n\t\t\tvar n int\n\t\t\trequire.NoError(t, db.QueryRow(\"SELECT COUNT(*) FROM `friendships`\").Scan(&n))\n\t\t\trequire.Equal(t, 2, n)\n\n\t\t\t// Apply the rest.\n\t\t\ts, err = runCmd(\n\t\t\t\tmigrateApplyCmd(),\n\t\t\t\t\"--dir\", \"file://testdata/sqlitetx\",\n\t\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test.db\")),\n\t\t\t\t\"--tx-mode\", mode,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, db.QueryRow(\"SELECT COUNT(*) FROM `friendships`\").Scan(&n))\n\t\t\trequire.Equal(t, 2, n)\n\n\t\t\t// For transactions check that the foreign keys are checked before the transaction is committed.\n\t\t\tif mode != \"none\" {\n\t\t\t\t// Apply the first 2 migrations for the faulty one.\n\t\t\t\ts, err = runCmd(\n\t\t\t\t\tmigrateApplyCmd(),\n\t\t\t\t\t\"--dir\", \"file://testdata/sqlitetx2\",\n\t\t\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test_2.db\")),\n\t\t\t\t\t\"--tx-mode\", mode,\n\t\t\t\t\t\"2\",\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotEmpty(t, s)\n\t\t\t\tdb, err = sql.Open(\"sqlite3\", fmt.Sprintf(\"file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test_2.db\")))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NoError(t, db.QueryRow(\"SELECT COUNT(*) FROM `friendships`\").Scan(&n))\n\t\t\t\trequire.Equal(t, 2, n)\n\n\t\t\t\t// Add an existing constraint.\n\t\t\t\tc, err := sqlclient.Open(context.Background(), fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test_2.db\")))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\t_, err = c.ExecContext(context.Background(), \"PRAGMA foreign_keys = off; INSERT INTO `friendships` (`user_id`, `friend_id`) VALUES (3,3);PRAGMA foreign_keys = on;\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NoError(t, db.QueryRow(\"SELECT COUNT(*) FROM `friendships`\").Scan(&n))\n\t\t\t\trequire.Equal(t, 3, n)\n\n\t\t\t\t// Apply the rest, expect it to fail due to constraint error, but only the new one is reported.\n\t\t\t\ts, err = runCmd(\n\t\t\t\t\tmigrateApplyCmd(),\n\t\t\t\t\t\"--dir\", \"file://testdata/sqlitetx2\",\n\t\t\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test_2.db\")),\n\t\t\t\t\t\"--tx-mode\", mode,\n\t\t\t\t)\n\t\t\t\trequire.EqualError(t, err, \"sql/sqlite: foreign key mismatch: [{tbl:friendships ref:users row:4 index:1}]\")\n\t\t\t\trequire.NoError(t, db.QueryRow(\"SELECT COUNT(*) FROM `friendships`\").Scan(&n))\n\t\t\t\trequire.Equal(t, 3, n) // was rolled back\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestMigrate_ApplyTxModeDirective(t *testing.T) {\n\tfor _, mode := range []string{txModeNone, txModeFile} {\n\t\tu := openSQLite(t, \"\")\n\t\t_, err := runCmd(\n\t\t\tmigrateApplyCmd(),\n\t\t\t\"--dir\", \"file://testdata/sqlitetx3\",\n\t\t\t\"--url\", u,\n\t\t\t\"--tx-mode\", mode,\n\t\t)\n\t\trequire.EqualError(t, err, `sql/migrate: executing statement \"INSERT INTO t1 VALUES (1), (1);\" from version \"20220925094021\": UNIQUE constraint failed: t1.a`)\n\t\tdb, err := sql.Open(\"sqlite3\", strings.TrimPrefix(u, \"sqlite://\"))\n\t\trequire.NoError(t, err)\n\t\tvar n int\n\t\trequire.NoError(t, db.QueryRow(\"SELECT COUNT(*) FROM sqlite_master WHERE name IN ('atlas_schema_revisions', 'users', 't1')\").Scan(&n))\n\t\trequire.Equal(t, 3, n)\n\t\trequire.NoError(t, db.Close())\n\t}\n\n\t_, err := runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlitetx3\",\n\t\t\"--url\", \"sqlite://txmode?mode=memory&_fk=1\",\n\t\t\"--tx-mode\", txModeAll,\n\t)\n\trequire.EqualError(t, err, `cannot set txmode directive to \"none\" in \"20220925094021_second.sql\" when txmode \"all\" is set globally`)\n\n\ts, err := runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlitetx4\",\n\t\t\"--url\", \"sqlite://txmode?mode=memory&_fk=1\",\n\t\t\"--tx-mode\", txModeAll,\n\t\t\"--log\", \"{{ .Error }}\",\n\t)\n\trequire.EqualError(t, err, `unknown txmode \"unknown\" found in file directive \"20220925094021_second.sql\"`)\n\t// Errors should be attached to the report.\n\trequire.Equal(t, s, `unknown txmode \"unknown\" found in file directive \"20220925094021_second.sql\"`)\n}\n\nfunc TestMigrate_ApplyExecOrder(t *testing.T) {\n\tp := t.TempDir()\n\tdb := fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test.db\"))\n\trequire.NoError(t, os.Mkdir(filepath.Join(p, \"migrations\"), 0700))\n\tdir, err := migrate.NewLocalDir(filepath.Join(p, \"migrations\"))\n\trequire.NoError(t, err)\n\twrite := func(n, b string) {\n\t\trequire.NoError(t, dir.WriteFile(n, []byte(b)))\n\t\thash, err := dir.Checksum()\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, migrate.WriteSumFile(dir, hash))\n\t}\n\twrite(\"1.sql\", \"create table t1(c int);\")\n\twrite(\"3.sql\", \"create table t3(c int);\")\n\n\t// First run.\n\ts, err := runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://\"+dir.Path(),\n\t\t\"--url\", db,\n\t\t\"--format\", \"{{ len .Applied }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"2\", s)\n\n\t// File was added out of order.\n\twrite(\"2.sql\", \"create table t2(c int);\")\n\t_, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://\"+dir.Path(),\n\t\t\"--url\", db,\n\t)\n\trequire.EqualError(t, err, \"migration file 2.sql was added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error\")\n\n\t// The \"linear\" option is the default execution order.\n\t_, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://\"+dir.Path(),\n\t\t\"--url\", db,\n\t\t\"--exec-order\", \"linear\",\n\t)\n\trequire.EqualError(t, err, \"migration file 2.sql was added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error\")\n\n\t// Keep linear order and skip files that were added out of order.\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://\"+dir.Path(),\n\t\t\"--url\", db,\n\t\t\"--exec-order\", \"linear-skip\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"No migration files to execute\\n\", s)\n\n\t// Allow non-linear order.\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://\"+dir.Path(),\n\t\t\"--url\", db,\n\t\t\"--exec-order\", \"non-linear\",\n\t\t\"--format\", \"{{ range .Applied }}{{ .Version }}{{ end }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"2\", s)\n\n\twrite(\"2.5.sql\", \"create table t25(c int);\")\n\twrite(\"4.sql\", \"create table t4(c int);\")\n\ts, err = runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://\"+dir.Path(),\n\t\t\"--url\", db,\n\t\t\"--exec-order\", \"non-linear\",\n\t\t\"--format\", \"{{ range .Applied }}{{ println .Version }}{{ end }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"2.5\\n4\\n\", s)\n\n\t// There are no pending migrations, in all execution orders.\n\tfor _, o := range []string{\"linear\", \"linear-skip\", \"non-linear\"} {\n\t\ts, err = runCmd(\n\t\t\tmigrateApplyCmd(),\n\t\t\t\"--dir\", \"file://\"+dir.Path(),\n\t\t\t\"--url\", db,\n\t\t\t\"--exec-order\", o,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"No migration files to execute\\n\", s)\n\t}\n}\n\nfunc TestMigrate_ApplyBaseline(t *testing.T) {\n\tt.Run(\"FromFlags\", func(t *testing.T) {\n\t\tp := t.TempDir()\n\t\t// Run migration with baseline should store this revision in the database.\n\t\ts, err := runCmd(\n\t\t\tmigrateApplyCmd(),\n\t\t\t\"--dir\", \"file://testdata/baseline1\",\n\t\t\t\"--baseline\", \"1\",\n\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test1.db\")),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Contains(t, s, \"No migration files to execute\")\n\t\t// Next run without baseline should run the migration from the baseline.\n\t\ts, err = runCmd(\n\t\t\tmigrateApplyCmd(),\n\t\t\t\"--dir\", \"file://testdata/baseline1\",\n\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test1.db\")),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Contains(t, s, \"No migration files to execute\")\n\n\t\t// Multiple migration files with baseline.\n\t\ts, err = runCmd(\n\t\t\tmigrateApplyCmd(),\n\t\t\t\"--dir\", \"file://testdata/baseline2\",\n\t\t\t\"--baseline\", \"1\",\n\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test2.db\")),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Contains(t, s, \"Migrating to version 20220318104615 from 1 (2 migrations in total)\")\n\n\t\t// Run all migration files and skip baseline.\n\t\ts, err = runCmd(\n\t\t\tmigrateApplyCmd(),\n\t\t\t\"--dir\", \"file://testdata/baseline2\",\n\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test3.db\")),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Contains(t, s, \"Migrating to version 20220318104615 (3 migrations in total)\")\n\t})\n\n\tt.Run(\"FromConfig\", func(t *testing.T) {\n\t\tconst h = `\nenv \"local\" {\n  migration {\n    baseline = \"1\"\n  }\n}`\n\t\tp := t.TempDir()\n\t\tpath := filepath.Join(p, \"atlas.hcl\")\n\t\terr := os.WriteFile(path, []byte(h), 0600)\n\t\trequire.NoError(t, err)\n\t\tcmd := migrateCmd()\n\t\tcmd.AddCommand(migrateApplyCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-c\", \"file://\"+path,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--dir\", \"file://testdata/baseline1\",\n\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test1.db\")),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Contains(t, s, \"No migration files to execute\")\n\n\t\tcmd = migrateCmd()\n\t\tcmd.AddCommand(migrateApplyCmd())\n\t\ts, err = runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-c\", \"file://\"+path,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--dir\", \"file://testdata/baseline2\",\n\t\t\t\"--url\", fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test2.db\")),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Contains(t, s, \"Migrating to version 20220318104615 from 1 (2 migrations in total)\")\n\t})\n}\n\nfunc TestMigrate_Diff(t *testing.T) {\n\tp := t.TempDir()\n\tto := hclURL(t)\n\n\t// Will create migration directory if not existing.\n\t_, err := runCmd(\n\t\tmigrateDiffCmd(),\n\t\t\"name\",\n\t\t\"--dir\", \"file://\"+filepath.Join(p, \"migrations\"),\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\"--to\", to,\n\t)\n\trequire.NoError(t, err)\n\trequire.FileExists(t, filepath.Join(p, \"migrations\", fmt.Sprintf(\"%s_name.sql\", time.Now().UTC().Format(\"20060102150405\"))))\n\n\t// Expect no clean dev error.\n\tp = t.TempDir()\n\ts, err := runCmd(\n\t\tmigrateDiffCmd(),\n\t\t\"name\",\n\t\t\"--dir\", \"file://\"+p,\n\t\t\"--dev-url\", openSQLite(t, \"create table t (c int);\"),\n\t\t\"--to\", to,\n\t)\n\trequire.ErrorAs(t, err, new(*migrate.NotCleanError))\n\trequire.ErrorContains(t, err, \"found table \\\"t\\\"\")\n\n\t// Works (on empty directory).\n\ts, err = runCmd(\n\t\tmigrateDiffCmd(),\n\t\t\"name\",\n\t\t\"--dir\", \"file://\"+p,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\"--to\", to,\n\t)\n\trequire.NoError(t, err)\n\trequire.Zero(t, s)\n\trequire.FileExists(t, filepath.Join(p, fmt.Sprintf(\"%s_name.sql\", time.Now().UTC().Format(\"20060102150405\"))))\n\trequire.FileExists(t, filepath.Join(p, \"atlas.sum\"))\n\n\t// A lock will prevent diffing.\n\tsqlclient.Register(\"sqlitelockdiff\", sqlclient.OpenerFunc(func(ctx context.Context, u *url.URL) (*sqlclient.Client, error) {\n\t\tu.Scheme = \"sqlite\"\n\t\tclient, err := sqlclient.OpenURL(ctx, u)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tclient.Driver = &sqliteLockerDriver{Driver: client.Driver}\n\t\treturn client, nil\n\t}))\n\tf, err := os.Create(filepath.Join(p, \"test.db\"))\n\trequire.NoError(t, err)\n\trequire.NoError(t, f.Close())\n\ts, err = runCmd(\n\t\tmigrateDiffCmd(),\n\t\t\"name\",\n\t\t\"--dir\", \"file://\"+t.TempDir(),\n\t\t\"--dev-url\", fmt.Sprintf(\"sqlitelockdiff://file:%s?cache=shared&_fk=1\", filepath.Join(p, \"test.db\")),\n\t\t\"--to\", to,\n\t)\n\trequire.True(t, strings.HasPrefix(s, \"Error: acquiring database lock: \"+errLock.Error()))\n\trequire.ErrorIs(t, err, errLock)\n\n\tt.Run(\"Edit\", func(t *testing.T) {\n\t\tp := t.TempDir()\n\t\tt.Setenv(\"EDITOR\", \"echo '-- Comment' >>\")\n\t\targs := []string{\n\t\t\t\"--edit\",\n\t\t\t\"--dir\", \"file://\" + p,\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", to,\n\t\t}\n\t\t_, err := runCmd(migrateDiffCmd(), args...)\n\t\tfiles, err := os.ReadDir(p)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 2)\n\t\tb, err := os.ReadFile(filepath.Join(p, files[0].Name()))\n\t\trequire.NoError(t, err)\n\t\trequire.Contains(t, string(b), \"CREATE\")\n\t\trequire.True(t, strings.HasSuffix(string(b), \"-- Comment\\n\"))\n\t\trequire.Equal(t, \"atlas.sum\", files[1].Name())\n\n\t\t// Second run will have no effect.\n\t\t_, err = runCmd(migrateDiffCmd(), args...)\n\t\trequire.NoError(t, err)\n\t\tfiles, err = os.ReadDir(p)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 2)\n\t})\n\n\tt.Run(\"Format\", func(t *testing.T) {\n\t\tfor f, out := range map[string]string{\n\t\t\t\"{{sql .}}\":            \"CREATE TABLE `t` (`c` int NULL);\",\n\t\t\t`{{- sql . \"  \" -}}`:   \"CREATE TABLE `t` (\\n  `c` int NULL\\n);\",\n\t\t\t\"{{ sql . \\\"\\t\\\" }}\":   \"CREATE TABLE `t` (\\n\\t`c` int NULL\\n);\",\n\t\t\t\"{{sql $ \\\"  \\t  \\\"}}\": \"CREATE TABLE `t` (\\n  \\t  `c` int NULL\\n);\",\n\t\t} {\n\t\t\tp := t.TempDir()\n\t\t\td, err := migrate.NewLocalDir(p)\n\t\t\trequire.NoError(t, err)\n\t\t\t// Works with indentation.\n\t\t\ts, err = runCmd(\n\t\t\t\tmigrateDiffCmd(),\n\t\t\t\t\"name\",\n\t\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\t\"--to\", openSQLite(t, \"create table t (c int);\"),\n\t\t\t\t\"--format\", f,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Zero(t, s)\n\t\t\tfiles, err := d.Files()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, files, 1)\n\t\t\trequire.Equal(t, \"-- Create \\\"t\\\" table\\n\"+out+\"\\n\", string(files[0].Bytes()))\n\t\t}\n\n\t\t// Invalid use of sql.\n\t\ts, err = runCmd(\n\t\t\tmigrateDiffCmd(),\n\t\t\t\"name\",\n\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", openSQLite(t, \"create table t (c int);\"),\n\t\t\t\"--format\", `{{ if . }}{{ sql . \"  \" }}{{ end }}`,\n\t\t)\n\t\trequire.EqualError(t, err, `'sql' can only be used to indent statements. got: {{if .}}{{sql . \"  \"}}{{end}}`)\n\n\t\t// Valid template.\n\t\tp := t.TempDir()\n\t\td, err := migrate.NewLocalDir(p)\n\t\trequire.NoError(t, err)\n\t\ts, err = runCmd(\n\t\t\tmigrateDiffCmd(),\n\t\t\t\"name\",\n\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", openSQLite(t, \"create table t (c int);\"),\n\t\t\t\"--format\", `{{ range .Changes }}{{ .Cmd }}{{ end }}`,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\tfiles, err := d.Files()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 1)\n\t\trequire.Equal(t, \"CREATE TABLE `t` (`c` int NULL)\", string(files[0].Bytes()))\n\t})\n\n\tt.Run(\"ProjectFile\", func(t *testing.T) {\n\t\tp := t.TempDir()\n\t\th := `\nvariable \"schema\" {\n  type = string\n}\n\nvariable \"dir\" {\n  type = string\n}\n\nvariable \"destructive\" {\n  type = bool\n  default = false\n}\n\nenv \"local\" {\n  src = \"file://${var.schema}\"\n  dev = \"sqlite://ci?mode=memory&_fk=1\"\n  migration {\n    dir = \"file://${var.dir}\"\n  }\n  diff {\n    skip {\n      drop_column = !var.destructive\n    }\n  }\n}\n`\n\t\tpathC := filepath.Join(p, \"atlas.hcl\")\n\t\trequire.NoError(t, os.WriteFile(pathC, []byte(h), 0600))\n\t\tpathS := filepath.Join(p, \"schema.sql\")\n\t\trequire.NoError(t, os.WriteFile(pathS, []byte(`CREATE TABLE t(c1 int, c2 int);`), 0600))\n\t\tpathD := t.TempDir()\n\t\tcmd := migrateCmd()\n\t\tcmd.AddCommand(migrateDiffCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"diff\", \"initial\",\n\t\t\t\"-c\", \"file://\"+pathC,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", \"schema=\"+pathS,\n\t\t\t\"--var\", \"dir=\"+pathD,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, s)\n\t\td, err := migrate.NewLocalDir(pathD)\n\t\trequire.NoError(t, err)\n\t\tfiles, err := d.Files()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 1)\n\t\trequire.Equal(t, \"-- Create \\\"t\\\" table\\nCREATE TABLE `t` (`c1` int NULL, `c2` int NULL);\\n\", string(files[0].Bytes()))\n\n\t\t// Drop column should be skipped.\n\t\trequire.NoError(t, os.WriteFile(pathS, []byte(`CREATE TABLE t(c1 int);`), 0600))\n\t\tcmd = migrateCmd()\n\t\tcmd.AddCommand(migrateDiffCmd())\n\t\ts, err = runCmd(\n\t\t\tcmd, \"diff\", \"no_change\",\n\t\t\t\"-c\", \"file://\"+pathC,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", \"schema=\"+pathS,\n\t\t\t\"--var\", \"dir=\"+pathD,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"The migration directory is synced with the desired state, no changes to be made\\n\", s)\n\t\tfiles, err = d.Files()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 1)\n\n\t\t// Column is dropped when destructive is true.\n\t\tcmd = migrateCmd()\n\t\tcmd.AddCommand(migrateDiffCmd())\n\t\ts, err = runCmd(\n\t\t\tcmd, \"diff\", \"second\",\n\t\t\t\"-c\", \"file://\"+pathC,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", \"schema=\"+pathS,\n\t\t\t\"--var\", \"dir=\"+pathD,\n\t\t\t\"--var\", \"destructive=true\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, s)\n\t\tfiles, err = d.Files()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 2)\n\t})\n\n\tt.Run(\"TemplateDir\", func(t *testing.T) {\n\t\tvar (\n\t\t\th = `\nvariable \"default\" {\n  type    = string\n  default = \"Default\"\n}\n\nvariable \"schema_path\" {\n  type = string\n}\n\nvariable \"migrations_path\" {\n  type = string\n}\n\ndata \"hcl_schema\" \"app\" {\n  path = var.schema_path\n  vars = {\n    default = var.default\n  }\n}\n\ndata \"template_dir\" \"app\" {\n  path = var.migrations_path\n  vars = {\n    default = var.default\n  }\n}\n\nenv \"local\" {\n  src = data.hcl_schema.app.url\n  dev = \"sqlite://file?mode=memory&_fk=1\"\n  migration {\n    dir = data.template_dir.app.url\n  }\n}\n`\n\t\t\tp, md      = t.TempDir(), t.TempDir()\n\t\t\tcfg, state = filepath.Join(p, \"atlas.hcl\"), filepath.Join(p, \"schema.hcl\")\n\t\t)\n\t\terr := os.WriteFile(cfg, []byte(h), 0600)\n\t\trequire.NoError(t, err)\n\t\terr = os.WriteFile(state, []byte(`variable \"default\" { type = string  }\nschema \"main\" {}\ntable \"users\" {\n  schema = schema.main\n  column \"c\" {\n    type = text\n    default = var.default\n  }\n}\n`), 0600)\n\t\trequire.NoError(t, err)\n\t\tdir, err := migrate.NewLocalDir(md)\n\t\trequire.NoError(t, err)\n\t\terr = dir.WriteFile(\"1.sql\", []byte(`create table users (c text default \"{{ .default }}\" NOT NULL);`))\n\t\trequire.NoError(t, err)\n\n\t\tcmd := migrateCmd()\n\t\tcmd.AddCommand(migrateHashCmd())\n\t\t_, err = runCmd(\n\t\t\tcmd, \"hash\",\n\t\t\t\"--dir\", \"file://\"+md,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\tf, err := dir.Open(migrate.HashFileName)\n\t\trequire.NoError(t, err)\n\t\tb, err := io.ReadAll(f)\n\t\trequire.NoError(t, err)\n\t\trequire.NotEmpty(t, b)\n\n\t\tcmd = migrateCmd()\n\t\tcmd.AddCommand(migrateDiffCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"diff\",\n\t\t\t\"-c\", \"file://\"+cfg,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", \"migrations_path=\"+md,\n\t\t\t\"--var\", \"schema_path=\"+state,\n\t\t)\n\t\t// Desired state and migration directory are in sync.\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"The migration directory is synced with the desired state, no changes to be made\\n\", s)\n\t\tf, err = dir.Open(migrate.HashFileName)\n\t\trequire.NoError(t, err)\n\t\tnb, err := io.ReadAll(f)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, b, nb, \"hash file should not be updated\")\n\n\t\t// Update the desired state and run diff again.\n\t\terr = os.WriteFile(state, []byte(`variable \"default\" { type = string  }\nschema \"main\" {}\ntable \"users\" {\n  schema = schema.main\n  column \"c\" {\n    type = text\n    default = var.default\n  }\n  column \"d\" {\n    type = text\n  }\n}\n`), 0600)\n\t\trequire.NoError(t, err)\n\t\t_, err = runCmd(\n\t\t\tcmd, \"diff\",\n\t\t\t\"-c\", \"file://\"+cfg,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", \"migrations_path=\"+md,\n\t\t\t\"--var\", \"schema_path=\"+state,\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\t// Check files.\n\t\tfiles, err := dir.Files()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 2)\n\t\trequire.Equal(t, \"1.sql\", files[0].Name())\n\t\trequire.Equal(t, `create table users (c text default \"{{ .default }}\" NOT NULL);`, string(files[0].Bytes()), \"should not update template files\")\n\t\trequire.Equal(t, \"-- Add column \\\"d\\\" to table: \\\"users\\\"\\nALTER TABLE `users` ADD COLUMN `d` text NOT NULL;\\n\", string(files[1].Bytes()))\n\n\t\t// Ensure the sum file is consistent.\n\t\tf, err = dir.Open(migrate.HashFileName)\n\t\trequire.NoError(t, err)\n\t\tbefore, err := io.ReadAll(f)\n\t\trequire.NoError(t, err)\n\t\tcmd = migrateCmd()\n\t\tcmd.AddCommand(migrateHashCmd())\n\t\t_, err = runCmd(\n\t\t\tcmd, \"hash\",\n\t\t\t\"--dir\", \"file://\"+md,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\tf, err = dir.Open(migrate.HashFileName)\n\t\trequire.NoError(t, err)\n\t\tafter, err := io.ReadAll(f)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, before, after)\n\t})\n}\n\nfunc TestMigrate_StatusJSON(t *testing.T) {\n\tp := t.TempDir()\n\ts, err := runCmd(\n\t\tmigrateStatusCmd(),\n\t\t\"--dir\", \"file://\"+p,\n\t\t\"-u\", openSQLite(t, \"\"),\n\t\t\"--format\", \"{{ json .Env.Driver }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `\"sqlite\"`, s)\n}\n\nfunc TestMigrate_Set(t *testing.T) {\n\tu := fmt.Sprintf(\"sqlite://file:%s?_fk=1\", filepath.Join(t.TempDir(), \"test.db\"))\n\t_, err := runCmd(\n\t\tmigrateApplyCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite\",\n\t\t\"--url\", u,\n\t)\n\trequire.NoError(t, err)\n\n\ts, err := runCmd(\n\t\tmigrateSetCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite\",\n\t\t\"-u\", u,\n\t\t\"20220318104614\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `Current version is 20220318104614 (1 removed):\n\n  - 20220318104615 (second)\n\n`, s)\n\ts, err = runCmd(\n\t\tmigrateSetCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite\",\n\t\t\"-u\", u,\n\t\t\"20220318104615\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `Current version is 20220318104615 (1 set):\n\n  + 20220318104615 (second)\n\n`, s)\n\n\ts, err = runCmd(\n\t\tmigrateSetCmd(),\n\t\t\"--dir\", \"file://testdata/baseline1\",\n\t\t\"-u\", u,\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `Current version is 1 (1 set, 2 removed):\n\n  + 1 (baseline)\n  - 20220318104614 (initial)\n  - 20220318104615 (second)\n\n`, s)\n\n\ts, err = runCmd(\n\t\tmigrateSetCmd(),\n\t\t\"--dir\", filepath.Join(\"file://\", t.TempDir()), // empty dir.\n\t\t\"-u\", u,\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `All revisions deleted (1 in total):\n\n  - 1 (baseline)\n\n`, s)\n\n\t// Empty database.\n\tu = fmt.Sprintf(\"sqlite://file:%s?_fk=1\", filepath.Join(t.TempDir(), \"test.db\"))\n\t_, err = runCmd(\n\t\tmigrateSetCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite\",\n\t\t\"-u\", u,\n\t)\n\trequire.EqualError(t, err, \"accepts 1 arg(s), received 0\")\n\n\ts, err = runCmd(\n\t\tmigrateSetCmd(),\n\t\t\"--dir\", \"file://testdata/sqlite\",\n\t\t\"-u\", u,\n\t\t\"20220318104614\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `Current version is 20220318104614 (1 set):\n\n  + 20220318104614 (initial)\n\n`, s)\n}\n\nfunc TestMigrate_New(t *testing.T) {\n\tvar (\n\t\tp = t.TempDir()\n\t\tv = time.Now().UTC().Format(\"20060102150405\")\n\t)\n\n\ts, err := runCmd(migrateNewCmd(), \"--dir\", \"file://\"+p)\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\trequire.FileExists(t, filepath.Join(p, v+\".sql\"))\n\trequire.FileExists(t, filepath.Join(p, \"atlas.sum\"))\n\trequire.Equal(t, 2, countFiles(t, p))\n\n\ts, err = runCmd(migrateNewCmd(), \"my-migration-file\", \"--dir\", \"file://\"+p)\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\trequire.FileExists(t, filepath.Join(p, v+\"_my-migration-file.sql\"))\n\trequire.FileExists(t, filepath.Join(p, \"atlas.sum\"))\n\trequire.Equal(t, 3, countFiles(t, p))\n\n\tp = t.TempDir()\n\ts, err = runCmd(migrateNewCmd(), \"golang-migrate\", \"--dir\", \"file://\"+p, \"--dir-format\", migrate2.FormatGolangMigrate)\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\trequire.FileExists(t, filepath.Join(p, v+\"_golang-migrate.up.sql\"))\n\trequire.FileExists(t, filepath.Join(p, v+\"_golang-migrate.down.sql\"))\n\trequire.Equal(t, 3, countFiles(t, p))\n\n\tp = t.TempDir()\n\ts, err = runCmd(migrateNewCmd(), \"goose\", \"--dir\", \"file://\"+p+\"?format=\"+migrate2.FormatGoose)\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\trequire.FileExists(t, filepath.Join(p, v+\"_goose.sql\"))\n\trequire.Equal(t, 2, countFiles(t, p))\n\n\tp = t.TempDir()\n\ts, err = runCmd(migrateNewCmd(), \"flyway\", \"--dir\", \"file://\"+p+\"?format=\"+migrate2.FormatFlyway)\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\trequire.FileExists(t, filepath.Join(p, fmt.Sprintf(\"V%s__%s.sql\", v, migrate2.FormatFlyway)))\n\trequire.FileExists(t, filepath.Join(p, fmt.Sprintf(\"U%s__%s.sql\", v, migrate2.FormatFlyway)))\n\trequire.Equal(t, 3, countFiles(t, p))\n\n\tp = t.TempDir()\n\ts, err = runCmd(migrateNewCmd(), \"liquibase\", \"--dir\", \"file://\"+p+\"?format=\"+migrate2.FormatLiquibase)\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\trequire.FileExists(t, filepath.Join(p, v+\"_liquibase.sql\"))\n\trequire.Equal(t, 2, countFiles(t, p))\n\n\tp = t.TempDir()\n\ts, err = runCmd(migrateNewCmd(), \"dbmate\", \"--dir\", \"file://\"+p+\"?format=\"+migrate2.FormatDBMate)\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\trequire.FileExists(t, filepath.Join(p, v+\"_dbmate.sql\"))\n\trequire.Equal(t, 2, countFiles(t, p))\n\n\tf := filepath.Join(\"testdata\", \"mysql\", \"new.sql\")\n\trequire.NoError(t, os.WriteFile(f, []byte(\"contents\"), 0600))\n\tt.Cleanup(func() { os.Remove(f) })\n\ts, err = runCmd(migrateNewCmd(), \"--dir\", \"file://testdata/mysql\")\n\trequire.NotZero(t, s)\n\trequire.Error(t, err)\n\n\tt.Run(\"Edit\", func(t *testing.T) {\n\t\tp := t.TempDir()\n\t\trequire.NoError(t, os.Setenv(\"EDITOR\", \"echo 'contents' >\"))\n\t\tt.Cleanup(func() { require.NoError(t, os.Unsetenv(\"EDITOR\")) })\n\t\ts, err = runCmd(migrateNewCmd(), \"--dir\", \"file://\"+p, \"--edit\")\n\t\tfiles, err := os.ReadDir(p)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 2)\n\t\tb, err := os.ReadFile(filepath.Join(p, files[0].Name()))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"contents\\n\", string(b))\n\t\trequire.Equal(t, \"atlas.sum\", files[1].Name())\n\t})\n}\n\nfunc TestMigrate_Validate(t *testing.T) {\n\t// Without re-playing.\n\ts, err := runCmd(migrateValidateCmd(), \"--dir\", \"file://testdata/mysql\")\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\n\tf := filepath.Join(\"testdata\", \"mysql\", \"new.sql\")\n\trequire.NoError(t, os.WriteFile(f, []byte(\"contents\"), 0600))\n\tt.Cleanup(func() { os.Remove(f) })\n\ts, err = runCmd(migrateValidateCmd(), \"--dir\", \"file://testdata/mysql\")\n\trequire.NotZero(t, s)\n\trequire.Error(t, err)\n\trequire.NoError(t, os.Remove(f))\n\n\t// Replay migration files if a dev-url is given.\n\tp := t.TempDir()\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"1_initial.sql\"), []byte(\"create table t1 (c1 int)\"), 0644))\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"2_second.sql\"), []byte(\"create table t2 (c2 int)\"), 0644))\n\t_, err = runCmd(migrateHashCmd(), \"--dir\", \"file://\"+p)\n\trequire.NoError(t, err)\n\ts, err = runCmd(\n\t\tmigrateValidateCmd(),\n\t\t\"--dir\", \"file://\"+p,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t)\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\n\t// Should fail since the files are not compatible with SQLite.\n\t_, err = runCmd(migrateValidateCmd(), \"--dir\", \"file://testdata/mysql\", \"--dev-url\", openSQLite(t, \"\"))\n\trequire.Error(t, err)\n\n\t// Will report detailed information when there is a checksum mismatch.\n\tp = t.TempDir()\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"1_initial.sql\"), []byte(\"create table t1 (c1 int)\"), 0644))\n\ts, err = runCmd(migrateValidateCmd(), \"--dir\", \"file://\"+p)\n\trequire.ErrorIs(t, err, migrate.ErrChecksumNotFound)\n\trequire.Contains(t, s, \"You have a checksum error\")\n\t_, err = runCmd(migrateHashCmd(), \"--dir\", \"file://\"+p)\n\trequire.NoError(t, err)\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"2_second.sql\"), []byte(\"create table t2 (c2 int)\"), 0644))\n\ts, err = runCmd(migrateValidateCmd(), \"--dir\", \"file://\"+p)\n\tcsErr := &migrate.ChecksumError{}\n\trequire.ErrorAs(t, err, &csErr)\n\trequire.Equal(t, 3, csErr.Line)\n\trequire.Equal(t, \"2_second.sql\", csErr.File)\n\trequire.Equal(t, migrate.ReasonAdded, csErr.Reason)\n\trequire.Contains(t, s, \"You have a checksum error\")\n\trequire.Contains(t, s, \"L3: 2_second.sql was added\")\n}\n\nfunc TestMigrate_Hash(t *testing.T) {\n\ts, err := runCmd(migrateHashCmd(), \"--dir\", \"file://testdata/mysql\")\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\n\t// Prints a warning if --force flag is still used.\n\ts, err = runCmd(migrateHashCmd(), \"--dir\", \"file://testdata/mysql\", \"--force\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"Flag --force has been deprecated, you can safely omit it.\\n\", s)\n\n\tp := t.TempDir()\n\terr = copyFile(filepath.Join(\"testdata\", \"mysql\", \"20220318104614_initial.sql\"), filepath.Join(p, \"20220318104614_initial.sql\"))\n\trequire.NoError(t, err)\n\n\ts, err = runCmd(migrateHashCmd(), \"--dir\", \"file://\"+p)\n\trequire.Zero(t, s)\n\trequire.NoError(t, err)\n\trequire.FileExists(t, filepath.Join(p, \"atlas.sum\"))\n\td, err := os.ReadFile(filepath.Join(p, \"atlas.sum\"))\n\trequire.NoError(t, err)\n\tdir, err := migrate.NewLocalDir(p)\n\trequire.NoError(t, err)\n\tsum, err := dir.Checksum()\n\trequire.NoError(t, err)\n\tb, err := sum.MarshalText()\n\trequire.NoError(t, err)\n\trequire.Equal(t, d, b)\n\n\tp = t.TempDir()\n\trequire.NoError(t, copyFile(\n\t\tfilepath.Join(\"testdata\", \"mysql\", \"20220318104614_initial.sql\"),\n\t\tfilepath.Join(p, \"20220318104614_initial.sql\"),\n\t))\n\ts, err = runCmd(migrateHashCmd(), \"--dir\", \"file://\"+os.Getenv(\"MIGRATION_DIR\"))\n\trequire.NotZero(t, s)\n\trequire.Error(t, err)\n}\n\nfunc TestMigrate_Lint(t *testing.T) {\n\tp := t.TempDir()\n\ts, err := runCmd(\n\t\tmigrateLintCmd(),\n\t\t\"--dir\", \"file://\"+p,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\"--latest\", \"1\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Empty(t, s)\n\n\terr = os.WriteFile(filepath.Join(p, \"1.sql\"), []byte(\"CREATE TABLE t(c int);\"), 0600)\n\trequire.NoError(t, err)\n\terr = os.WriteFile(filepath.Join(p, \"2.sql\"), []byte(\"DROP TABLE t;\"), 0600)\n\trequire.NoError(t, err)\n\ts, err = runCmd(\n\t\tmigrateLintCmd(),\n\t\t\"--dir\", \"file://\"+p,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\"--latest\", \"1\",\n\t)\n\trequire.Error(t, err)\n\trequire.Regexp(t, `Analyzing changes from version 1 to 2 \\(1 migration in total\\):\n\n  -- analyzing version 2\n    -- destructive changes detected:\n      -- L1: Dropping table \"t\" https://atlasgo.io/lint/analyzers#DS102\n    -- suggested fix:\n      -> Add a pre-migration check to ensure table \"t\" is empty before dropping it\n  -- ok \\(.+\\)\n\n  -------------------------\n  -- .+\n  -- 1 version with errors\n  -- 1 schema change\n  -- 1 diagnostic\n`, s)\n\ts, err = runCmd(\n\t\tmigrateLintCmd(),\n\t\t\"--dir\", \"file://\"+p,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\"--latest\", \"1\",\n\t\t\"--log\", \"{{ range .Files }}{{ .Name }}{{ end }}\", // Backward compatibility with old flag name.\n\t)\n\trequire.Error(t, err)\n\trequire.Equal(t, \"2.sql\", s)\n\n\tt.Run(\"FromConfig\", func(t *testing.T) {\n\t\tcfg := filepath.Join(p, \"atlas.hcl\")\n\t\terr := os.WriteFile(cfg, []byte(`\nvariable \"error\" {\n  type    = bool\n  default = false\n}\n\nlint {\n  latest = 1\n  destructive {\n    error = var.error\n  }\n}\n`), 0600)\n\t\trequire.NoError(t, err)\n\t\tcmd := migrateCmd()\n\t\tcmd.AddCommand(migrateLintCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"lint\",\n\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"-c\", \"file://\"+cfg,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Regexp(t, `Analyzing changes from version 1 to 2 \\(1 migration in total\\):\n\n  -- analyzing version 2\n    -- destructive changes detected:\n      -- L1: Dropping table \"t\" https://atlasgo.io/lint/analyzers#DS102\n    -- suggested fix:\n      -> Add a pre-migration check to ensure table \"t\" is empty before dropping it\n  -- ok \\(.+\\)\n\n  -------------------------\n  -- .+\n  -- 1 version with warnings\n  -- 1 schema change\n  -- 1 diagnostic\n`, s)\n\n\t\tcmd = migrateCmd()\n\t\tcmd.AddCommand(migrateLintCmd())\n\t\ts, err = runCmd(\n\t\t\tcmd, \"lint\",\n\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"-c\", \"file://\"+cfg,\n\t\t\t\"--var\", \"error=true\",\n\t\t)\n\t\trequire.Error(t, err)\n\t\trequire.Regexp(t, `Analyzing changes from version 1 to 2 \\(1 migration in total\\):\n\n  -- analyzing version 2\n    -- destructive changes detected:\n      -- L1: Dropping table \"t\" https://atlasgo.io/lint/analyzers#DS102\n    -- suggested fix:\n      -> Add a pre-migration check to ensure table \"t\" is empty before dropping it\n  -- ok (.+)\n\n  -------------------------\n  -- .+\n  -- 1 version with errors\n  -- 1 schema change\n  -- 1 diagnostic\n`, s)\n\t})\n\n\t// Change files to golang-migrate format.\n\trequire.NoError(t, os.Rename(filepath.Join(p, \"1.sql\"), filepath.Join(p, \"1.up.sql\")))\n\trequire.NoError(t, os.Rename(filepath.Join(p, \"2.sql\"), filepath.Join(p, \"1.down.sql\")))\n\ts, err = runCmd(\n\t\tmigrateLintCmd(),\n\t\t\"--dir\", \"file://\"+p+\"?format=\"+migrate2.FormatGolangMigrate,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\"--latest\", \"2\",\n\t\t\"--format\", \"{{ range .Files }}{{ .Name }}:{{ len .Reports }}{{ end }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"1.up.sql:0\", s)\n\ts, err = runCmd(\n\t\tmigrateLintCmd(),\n\t\t\"--dir\", \"file://\"+p+\"?format=\"+migrate2.FormatGolangMigrate,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\"--latest\", \"2\",\n\t\t\"--format\", \"{{ range .Files }}{{ .Name }}:{{ len .Reports }}{{ end }}\",\n\t\t\"--dir-format\", migrate2.FormatGolangMigrate,\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"1.up.sql:0\", s)\n\n\t// Invalid files.\n\terr = os.WriteFile(filepath.Join(p, \"2.up.sql\"), []byte(\"BORING\"), 0600)\n\trequire.NoError(t, err)\n\ts, err = runCmd(\n\t\tmigrateLintCmd(),\n\t\t\"--dir\", \"file://\"+p+\"?format=\"+migrate2.FormatGolangMigrate,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\"--latest\", \"1\",\n\t)\n\trequire.Error(t, err)\n\trequire.Regexp(t, `Analyzing changes from version 1.up to 2.up \\(1 migration in total\\):\n\n  Error: executing statement: BORING: near \"BORING\": syntax error\n\n  -------------------------\n  -- .+\n  -- 1 version with errors\n`, s)\n}\n\nconst testSchema = `\nschema \"main\" {\n}\n\ntable \"table\" {\n  schema = schema.main\n  column \"col\" {\n    type    = int\n    comment = \"column comment\"\n  }\n  column \"age\" {\n    type = int\n  }\n  column \"price1\" {\n    type = int\n  }\n  column \"price2\" {\n    type           = int\n  }\n  column \"account_name\" {\n    type = varchar(32)\n    null = true\n  }\n  column \"created_at\" {\n    type    = datetime\n    default = sql(\"current_timestamp\")\n  }\n  primary_key {\n    columns = [table.table.column.col]\n  }\n  index \"index\" {\n    unique  = true\n    columns = [\n      table.table.column.col,\n      table.table.column.age,\n    ]\n  }\n  foreign_key \"accounts\" {\n    columns = [\n      table.table.column.account_name,\n    ]\n    ref_columns = [\n      table.accounts.column.name,\n    ]\n    on_delete = SET_NULL\n    on_update = \"NO_ACTION\"\n  }\n  check \"positive price\" {\n    expr = \"price1 > 0\"\n  }\n  check {\n    expr     = \"price1 <> price2\"\n  }\n  check {\n    expr     = \"price2 <> price1\"\n  }\n  comment        = \"table comment\"\n}\n\ntable \"accounts\" {\n  schema = schema.main\n  column \"name\" {\n    type = varchar(32)\n  }\n  column \"unsigned_float\" {\n    type     = float(10)\n    unsigned = true\n  }\n  column \"unsigned_decimal\" {\n    type     = decimal(10, 2)\n    unsigned = true\n  }\n  primary_key {\n    columns = [table.accounts.column.name]\n  }\n}`\n\nfunc hclURL(t *testing.T) string {\n\tp := t.TempDir()\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"schema.hcl\"), []byte(testSchema), 0600))\n\treturn \"file://\" + filepath.Join(p, \"schema.hcl\")\n}\n\nfunc copyFile(src, dst string) error {\n\tsf, err := os.Open(src)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer sf.Close()\n\tdf, err := os.Create(dst)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer df.Close()\n\t_, err = io.Copy(df, sf)\n\treturn err\n}\n\ntype sqliteLockerDriver struct{ migrate.Driver }\n\nvar errLock = errors.New(\"lockErr\")\n\nfunc (d *sqliteLockerDriver) Lock(context.Context, string, time.Duration) (schema.UnlockFunc, error) {\n\treturn func() error { return nil }, errLock\n}\n\nfunc countFiles(t *testing.T, p string) int {\n\tfiles, err := os.ReadDir(p)\n\trequire.NoError(t, err)\n\treturn len(files)\n}\n\nfunc sed(t *testing.T, r, p string) {\n\targs := []string{\"-i\"}\n\tif runtime.GOOS == \"darwin\" {\n\t\targs = append(args, \".bk\")\n\t}\n\tbuf, err := exec.Command(\"sed\", append(args, r, p)...).CombinedOutput()\n\trequire.NoError(t, err, string(buf))\n}\n\nfunc lines(f migrate.File) []string {\n\treturn strings.Split(strings.TrimSpace(string(f.Bytes())), \"\\n\")\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/project.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdapi\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cloudapi\"\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdext\"\n\tcmdmigrate \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/hashicorp/hcl/v2/hclsyntax\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/zclconf/go-cty/cty\"\n\t\"github.com/zclconf/go-cty/cty/function\"\n)\n\ntype (\n\t// Env represents an Atlas environment.\n\tEnv struct {\n\t\t// Name for this environment.\n\t\tName string `spec:\"name,name\"`\n\n\t\t// URL of the database.\n\t\tURL string `spec:\"url\"`\n\n\t\t// URL of the dev-database for this environment.\n\t\t// See: https://atlasgo.io/dev-database\n\t\tDevURL string `spec:\"dev\"`\n\n\t\t// List of schemas in this database that are managed by Atlas.\n\t\tSchemas []string `spec:\"schemas\"`\n\n\t\t// Exclude defines a list of glob patterns used to filter\n\t\t// resources on inspection.\n\t\tExclude []string `spec:\"exclude\"`\n\n\t\t// Include defines a list of glob patterns used to keep\n\t\t// resources on inspection.\n\t\tInclude []string `spec:\"include\"`\n\n\t\t// Schema containing the schema configuration of the env.\n\t\tSchema *Schema `spec:\"schema\"`\n\n\t\t// Migration containing the migration configuration of the env.\n\t\tMigration *Migration `spec:\"migration\"`\n\n\t\t// Diff policy of the environment.\n\t\tDiff *Diff `spec:\"diff\"`\n\n\t\t// Lint policy of the environment.\n\t\tLint *Lint `spec:\"lint\"`\n\n\t\t// Format of the environment.\n\t\tFormat Format `spec:\"format\"`\n\n\t\t// Test configuration of the environment.\n\t\tTest *Test `spec:\"test\"`\n\n\t\tschemahcl.DefaultExtension\n\t\tcloud  *cmdext.AtlasConfig\n\t\tconfig *Project\n\t}\n\n\t// Migration represents the migration directory for the Env.\n\tMigration struct {\n\t\tDir             string   `spec:\"dir\"`\n\t\tExclude         []string `spec:\"exclude\"`\n\t\tFormat          string   `spec:\"format\"`\n\t\tBaseline        string   `spec:\"baseline\"`\n\t\tExecOrder       string   `spec:\"exec_order\"`\n\t\tLockTimeout     string   `spec:\"lock_timeout\"`\n\t\tRevisionsSchema string   `spec:\"revisions_schema\"`\n\t\tRepo            *Repo    `spec:\"repo\"`\n\t}\n\n\t// Schema represents a schema in the registry.\n\tSchema struct {\n\t\t// The extension holds the \"src\" attribute.\n\t\t// It can be a string, or a list of strings.\n\t\tschemahcl.DefaultExtension\n\t\tRepo *Repo `spec:\"repo\"`\n\t}\n\n\t// Repo represents a repository in the schema registry\n\t// for a schema or migrations directory.\n\tRepo struct {\n\t\tName string `spec:\"name\"` // Name of the repository.\n\t}\n\n\t// Lint represents the configuration of migration linting.\n\tLint struct {\n\t\t// Format configures the --format option.\n\t\tFormat string `spec:\"log\"`\n\t\t// Latest configures the --latest option.\n\t\tLatest int `spec:\"latest\"`\n\t\tGit    struct {\n\t\t\t// Dir configures the --git-dir option.\n\t\t\tDir string `spec:\"dir\"`\n\t\t\t// Base configures the --git-base option.\n\t\t\tBase string `spec:\"base\"`\n\t\t} `spec:\"git\"`\n\t\t// Review defines when Atlas will ask the user to review and approve the changes.\n\t\tReview string `spec:\"review\"`\n\t\tschemahcl.DefaultExtension\n\t}\n\n\t// Diff represents the schema diffing policy.\n\tDiff struct {\n\t\t// SkipChanges configures the skip changes policy.\n\t\tSkipChanges *SkipChanges `spec:\"skip\"`\n\t\tschemahcl.DefaultExtension\n\t}\n\n\t// Test represents the test configuration of a project or environment.\n\tTest struct {\n\t\t// Schema represents the 'schema test' configuration.\n\t\tSchema struct {\n\t\t\tSrc  []string `spec:\"src\"`\n\t\t\tVars Vars     `spec:\"vars\"`\n\t\t} `spec:\"schema\"`\n\t\t// Migrate represents the 'migrate test' configuration.\n\t\tMigrate struct {\n\t\t\tSrc  []string `spec:\"src\"`\n\t\t\tVars Vars     `spec:\"vars\"`\n\t\t} `spec:\"migrate\"`\n\t}\n\n\t// SkipChanges represents the skip changes policy.\n\tSkipChanges struct {\n\t\tAddSchema        bool `spec:\"add_schema\"`\n\t\tDropSchema       bool `spec:\"drop_schema\"`\n\t\tModifySchema     bool `spec:\"modify_schema\"`\n\t\tAddTable         bool `spec:\"add_table\"`\n\t\tDropTable        bool `spec:\"drop_table\"`\n\t\tModifyTable      bool `spec:\"modify_table\"`\n\t\tRenameTable      bool `spec:\"rename_table\"`\n\t\tAddColumn        bool `spec:\"add_column\"`\n\t\tDropColumn       bool `spec:\"drop_column\"`\n\t\tModifyColumn     bool `spec:\"modify_column\"`\n\t\tAddIndex         bool `spec:\"add_index\"`\n\t\tDropIndex        bool `spec:\"drop_index\"`\n\t\tModifyIndex      bool `spec:\"modify_index\"`\n\t\tAddForeignKey    bool `spec:\"add_foreign_key\"`\n\t\tDropForeignKey   bool `spec:\"drop_foreign_key\"`\n\t\tModifyForeignKey bool `spec:\"modify_foreign_key\"`\n\t\tAddView          bool `spec:\"add_view\"`\n\t\tDropView         bool `spec:\"drop_view\"`\n\t\tModifyView       bool `spec:\"modify_view\"`\n\t\tRenameView       bool `spec:\"rename_view\"`\n\t\tAddFunc          bool `spec:\"add_func\"`\n\t\tDropFunc         bool `spec:\"drop_func\"`\n\t\tModifyFunc       bool `spec:\"modify_func\"`\n\t\tRenameFunc       bool `spec:\"rename_func\"`\n\t\tAddProc          bool `spec:\"add_proc\"`\n\t\tDropProc         bool `spec:\"drop_proc\"`\n\t\tModifyProc       bool `spec:\"modify_proc\"`\n\t\tRenameProc       bool `spec:\"rename_proc\"`\n\t\tAddTrigger       bool `spec:\"add_trigger\"`\n\t\tDropTrigger      bool `spec:\"drop_trigger\"`\n\t\tModifyTrigger    bool `spec:\"modify_trigger\"`\n\t\tRenameTrigger    bool `spec:\"rename_trigger\"`\n\t\tRenameConstraint bool `spec:\"rename_constraint\"`\n\t\tschemahcl.DefaultExtension\n\t}\n\n\t// Format represents the output formatting configuration of an environment.\n\tFormat struct {\n\t\tMigrate struct {\n\t\t\t// Apply configures the formatting for 'migrate apply'.\n\t\t\tApply string `spec:\"apply\"`\n\t\t\t// Down configures the formatting for 'migrate down'.\n\t\t\tDown string `spec:\"down\"`\n\t\t\t// Lint configures the formatting for 'migrate lint'.\n\t\t\tLint string `spec:\"lint\"`\n\t\t\t// Status configures the formatting for 'migrate status'.\n\t\t\tStatus string `spec:\"status\"`\n\t\t\t// Apply configures the formatting for 'migrate diff'.\n\t\t\tDiff string `spec:\"diff\"`\n\t\t} `spec:\"migrate\"`\n\t\tSchema struct {\n\t\t\t// Clean configures the formatting for 'schema clean'.\n\t\t\tClean string `spec:\"clean\"`\n\t\t\t// Inspect configures the formatting for 'schema inspect'.\n\t\t\tInspect string `spec:\"inspect\"`\n\t\t\t// Apply configures the formatting for 'schema apply'.\n\t\t\tApply string `spec:\"apply\"`\n\t\t\t// Apply configures the formatting for 'schema diff'.\n\t\t\tDiff string `spec:\"diff\"`\n\t\t\t// Push configures the formatting for 'schema push'.\n\t\t\tPush string `spec:\"push\"`\n\t\t} `spec:\"schema\"`\n\t\tschemahcl.DefaultExtension\n\t}\n)\n\n// envScheme defines the scheme that can be used to reference env attributes.\nconst envAttrScheme = \"env\"\n\n// MigrationRepo returns the migration repository name, if set.\nfunc (e *Env) MigrationRepo() (s string) {\n\tif e != nil && e.Migration != nil && e.Migration.Repo != nil {\n\t\ts = e.Migration.Repo.Name\n\t}\n\treturn\n}\n\n// MigrationExclude returns the exclusion patterns of the migration directory.\nfunc (e *Env) MigrationExclude() []string {\n\tif e != nil && e.Migration != nil {\n\t\treturn e.Migration.Exclude\n\t}\n\treturn nil\n}\n\n// SchemaRepo returns the desired schema repository name, if set.\nfunc (e *Env) SchemaRepo() (s string) {\n\tif e != nil && e.Schema != nil && e.Schema.Repo != nil {\n\t\ts = e.Schema.Repo.Name\n\t}\n\treturn\n}\n\n// LintReview returns the review mode for the lint command.\nfunc (e *Env) LintReview() string {\n\tif e != nil && e.Lint != nil && e.Lint.Review != \"\" {\n\t\treturn e.Lint.Review\n\t}\n\treturn ReviewAlways\n}\n\n// VarFromURL returns the string variable (env attribute) from the URL.\nfunc (e *Env) VarFromURL(s string) (string, error) {\n\tu, err := url.Parse(s)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif u.Host == \"\" || u.Path != \"\" || u.RawQuery != \"\" {\n\t\treturn \"\", fmt.Errorf(\"invalid env:// variable %q\", s)\n\t}\n\tvar sv string\n\tswitch u.Host {\n\tcase \"url\":\n\t\tsv = e.URL\n\tcase \"dev\":\n\t\tsv = e.DevURL\n\tcase \"src\", \"schema.src\":\n\t\tvar (\n\t\t\tok   bool\n\t\t\tattr *schemahcl.Attr\n\t\t)\n\t\tswitch {\n\t\tcase u.Host == \"src\":\n\t\t\tattr, ok = e.Attr(\"src\")\n\t\tcase e.Schema != nil:\n\t\t\tattr, ok = e.Schema.Attr(\"src\")\n\t\t}\n\t\tif !ok {\n\t\t\treturn \"\", fmt.Errorf(\"env://%s: no src attribute defined in env %q\", u.Host, e.Name)\n\t\t}\n\t\tswitch attr.V.Type() {\n\t\tcase cty.String:\n\t\t\ts, err := attr.String()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"env://%s: %w\", u.Host, err)\n\t\t\t}\n\t\t\treturn s, nil\n\t\tcase cty.List(cty.String):\n\t\t\tvs, err := attr.Strings()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"env://%s: %w\", u.Host, err)\n\t\t\t}\n\t\t\tif len(vs) != 0 {\n\t\t\t\treturn \"\", fmt.Errorf(\"env://%s: expect one schema in env %q, got %d\", u.Host, e.Name, len(vs))\n\t\t\t}\n\t\t\treturn vs[0], nil\n\t\tdefault:\n\t\t\treturn \"\", fmt.Errorf(\"env://%s: src attribute must be a string or list of strings, got %s\", u.Host, attr.V.Type().FriendlyName())\n\t\t}\n\tcase \"migration.dir\":\n\t\tif e.Migration == nil || e.Migration.Dir == \"\" {\n\t\t\treturn \"\", fmt.Errorf(\"env://%s: no migration dir defined in env %q\", u.Host, e.Name)\n\t\t}\n\t\tsv = e.Migration.Dir\n\tdefault:\n\t\tattr, ok := e.Attr(u.Host)\n\t\tif !ok {\n\t\t\treturn \"\", fmt.Errorf(\"env://%s (attribute) not found in env.%s\", u.Host, e.Name)\n\t\t}\n\t\tif sv, err = attr.String(); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"env://%s: %w\", u.Host, err)\n\t\t}\n\t}\n\tif strings.HasPrefix(sv, envAttrScheme+\"://\") {\n\t\treturn \"\", fmt.Errorf(\"env://%s (attribute) cannot reference another env://\", s)\n\t}\n\treturn sv, nil\n}\n\n// support backward compatibility with the 'log' attribute.\nfunc (e *Env) remainedLog() error {\n\tr, ok := e.Remain().Resource(\"log\")\n\tif ok {\n\t\treturn r.As(&e.Format)\n\t}\n\treturn nil\n}\n\n// Extend allows extending environment blocks with\n// a global one. For example:\n//\n//\tlint {\n//\t  log = <<EOS\n//\t    ...\n//\t  EOS\n//\t}\n//\n//\tenv \"local\" {\n//\t  ...\n//\t  lint {\n//\t    latest = 1\n//\t  }\n//\t}\n//\n//\tenv \"ci\" {\n//\t  ...\n//\t  lint {\n//\t    git {\n//\t      dir = \"../\"\n//\t      base = \"master\"\n//\t    }\n//\t  }\n//\t}\nfunc (l *Lint) Extend(global *Lint) *Lint {\n\tif l == nil {\n\t\treturn global\n\t}\n\tif l.Review == \"\" {\n\t\tl.Review = global.Review\n\t}\n\tif l.Format == \"\" {\n\t\tl.Format = global.Format\n\t}\n\tif len(l.Extra.Children) == 0 && len(l.Extra.Attrs) == 0 {\n\t\tl.Extra = global.Extra\n\t}\n\tswitch {\n\t// Changes detector was configured on the env.\n\tcase l.Git.Dir != \"\" && l.Git.Base != \"\" || l.Latest != 0:\n\t// Inherit global git detection.\n\tcase global.Git.Dir != \"\" || global.Git.Base != \"\":\n\t\tif global.Git.Dir != \"\" {\n\t\t\tl.Git.Dir = global.Git.Dir\n\t\t}\n\t\tif global.Git.Base != \"\" {\n\t\t\tl.Git.Base = global.Git.Base\n\t\t}\n\t// Inherit latest files configuration.\n\tcase global.Latest != 0:\n\t\tl.Latest = global.Latest\n\t}\n\treturn l\n}\n\n// support backward compatibility with the 'log' attribute.\nfunc (l *Lint) remainedLog() error {\n\tat, ok := l.Remain().Attr(\"log\")\n\tif !ok {\n\t\treturn nil\n\t}\n\tif l.Format != \"\" {\n\t\treturn fmt.Errorf(\"cannot use both 'log' and 'format' in the same lint block\")\n\t}\n\ts, err := at.String()\n\tif err != nil {\n\t\treturn err\n\t}\n\tl.Format = s\n\treturn nil\n}\n\n// Extend allows extending environment blocks with\n// a global one. For example:\n//\n//\tdiff {\n//\t  skip {\n//\t    drop_schema = true\n//\t  }\n//\t}\n//\n//\tenv \"local\" {\n//\t  ...\n//\t  diff {\n//\t    concurrent_index {\n//\t      create = true\n//\t      drop = true\n//\t    }\n//\t  }\n//\t}\nfunc (d *Diff) Extend(global *Diff) *Diff {\n\tif d == nil {\n\t\treturn global\n\t}\n\tif d.SkipChanges == nil {\n\t\td.SkipChanges = global.SkipChanges\n\t}\n\treturn d\n}\n\n// Options converts the diff policy into options.\nfunc (d *Diff) Options() (opts []schema.DiffOption) {\n\t// Per-driver configuration.\n\topts = append(opts, func(opts *schema.DiffOptions) {\n\t\tif d.SkipChanges != nil && d.SkipChanges.Remain() != nil {\n\t\t\td.DefaultExtension.Extra.Children = append(\n\t\t\t\td.DefaultExtension.Extra.Children,\n\t\t\t\t&schemahcl.Resource{\n\t\t\t\t\tType:  \"skip\",\n\t\t\t\t\tAttrs: d.SkipChanges.Remain().Attrs,\n\t\t\t\t})\n\t\t}\n\t\topts.Extra = d.DefaultExtension\n\t})\n\tif d.SkipChanges == nil {\n\t\treturn\n\t}\n\tvar (\n\t\tchanges schema.Changes\n\t\trv      = reflect.ValueOf(d.SkipChanges).Elem()\n\t)\n\tfor _, c := range []schema.Change{\n\t\t&schema.AddSchema{}, &schema.DropSchema{}, &schema.ModifySchema{},\n\t\t&schema.AddView{}, &schema.DropView{}, &schema.ModifyView{}, &schema.RenameView{},\n\t\t&schema.AddFunc{}, &schema.DropFunc{}, &schema.ModifyFunc{}, &schema.RenameFunc{},\n\t\t&schema.AddProc{}, &schema.DropProc{}, &schema.ModifyProc{}, &schema.RenameProc{},\n\t\t&schema.AddTrigger{}, &schema.DropTrigger{}, &schema.ModifyTrigger{}, &schema.RenameTrigger{},\n\t\t&schema.AddTable{}, &schema.DropTable{}, &schema.ModifyTable{}, &schema.RenameTable{},\n\t\t&schema.AddColumn{}, &schema.DropColumn{}, &schema.ModifyColumn{}, &schema.AddIndex{},\n\t\t&schema.DropIndex{}, &schema.ModifyIndex{}, &schema.AddForeignKey{}, &schema.DropForeignKey{},\n\t\t&schema.ModifyForeignKey{}, &schema.RenameConstraint{},\n\t} {\n\t\tif rt := reflect.TypeOf(c).Elem(); rv.FieldByName(rt.Name()).Bool() {\n\t\t\tchanges = append(changes, c)\n\t\t}\n\t}\n\tif len(changes) > 0 {\n\t\topts = append(opts, schema.DiffSkipChanges(changes...))\n\t}\n\treturn opts\n}\n\n// DiffOptions returns the diff options configured for the environment,\n// or nil if no environment or diff policy were set.\nfunc (e *Env) DiffOptions() []schema.DiffOption {\n\tif e == nil || e.Diff == nil {\n\t\treturn nil\n\t}\n\treturn e.Diff.Options()\n}\n\n// Sources returns the paths containing the Atlas desired schema.\n// The \"src\" attribute predates the \"schema\" block. If the \"schema\"\n// is defined, it takes precedence over the \"src\" attribute.\nfunc (e *Env) Sources() ([]string, error) {\n\tvar (\n\t\tok   bool\n\t\tattr *schemahcl.Attr\n\t)\n\tif attr, ok = e.Attr(\"src\"); !ok && e.Schema != nil {\n\t\tattr, ok = e.Schema.Attr(\"src\")\n\t}\n\tif !ok {\n\t\treturn nil, nil\n\t}\n\tswitch attr.V.Type() {\n\tcase cty.String:\n\t\ts, err := attr.String()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []string{s}, nil\n\tcase cty.List(cty.String):\n\t\treturn attr.Strings()\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"expected src to be either a string or strings, got: %s\", attr.V.Type().FriendlyName())\n\t}\n}\n\n// Vars returns the extra attributes stored in the Env as a map[string]cty.Value.\nfunc (e *Env) Vars() map[string]cty.Value {\n\tm := make(map[string]cty.Value, len(e.Extra.Attrs))\n\tfor _, attr := range e.Extra.Attrs {\n\t\tif attr.K == \"src\" {\n\t\t\tcontinue\n\t\t}\n\t\tm[attr.K] = attr.V\n\t}\n\t// For backward compatibility, we append the GlobalFlags as variables.\n\tfor k, v := range GlobalFlags.Vars {\n\t\tif _, ok := m[k]; !ok {\n\t\t\tm[k] = v\n\t\t}\n\t}\n\treturn m\n}\n\n// Extend allows extending environment blocks with\n// a global one. For example:\n//\n//\ttest {\n//\t  schema {\n//\t    src = [...]\n//\t  }\n//\t}\n//\n//\tenv \"local\" {\n//\t  ...\n//\t  test {\n//\t    schema {\n//\t      src = [...]\n//\t    }\n//\t  }\n//\t}\nfunc (t *Test) Extend(global *Test) *Test {\n\tif t == nil {\n\t\treturn global\n\t}\n\treturn t\n}\n\n// EnvByName parses and returns the project configuration with selected environments.\nfunc EnvByName(cmd *cobra.Command, name string, vars map[string]cty.Value) (*Project, []*Env, error) {\n\tenvs := make(map[string][]*Env)\n\tdefer func() {\n\t\tsetEnvs(cmd.Context(), envs[name])\n\t}()\n\tif p, e, ok := envsCache.load(GlobalFlags.ConfigURL, name, vars); ok {\n\t\treturn p, e, maySetLoginContext(cmd, p)\n\t}\n\tu, err := url.Parse(GlobalFlags.ConfigURL)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tswitch {\n\tcase u.Scheme == \"\":\n\t\treturn nil, nil, fmt.Errorf(\"missing scheme for config file. Did you mean file://%s?\", u)\n\tcase u.Scheme != \"file\":\n\t\treturn nil, nil, fmt.Errorf(\"unsupported config file driver %q\", u.Scheme)\n\t}\n\tpath := filepath.Join(u.Host, u.Path)\n\tif _, err := os.Stat(path); err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\terr = fmt.Errorf(\"config file %q was not found: %w\", path, err)\n\t\t}\n\t\treturn nil, nil, err\n\t}\n\tproject, err := parseConfig(cmd.Context(), path, name, vars)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\t// The atlas.hcl token predates 'atlas login' command. If exists,\n\t// attach it to the context to indicate the user is authenticated.\n\tif err := maySetLoginContext(cmd, project); err != nil {\n\t\treturn nil, nil, err\n\t}\n\tif err := project.Lint.remainedLog(); err != nil {\n\t\treturn nil, nil, err\n\t}\n\tfor _, e := range project.Envs {\n\t\tif e.Name == \"\" {\n\t\t\treturn nil, nil, fmt.Errorf(\"all envs must have names on file %q\", path)\n\t\t}\n\t\tif _, err := e.Sources(); err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\tif e.Migration == nil {\n\t\t\te.Migration = &Migration{}\n\t\t}\n\t\tif err := e.remainedLog(); err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\te.Diff = e.Diff.Extend(project.Diff)\n\t\te.Lint = e.Lint.Extend(project.Lint)\n\t\tif err := e.Lint.remainedLog(); err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\te.Test = e.Test.Extend(project.Test)\n\t\tenvs[e.Name] = append(envs[e.Name], e)\n\t}\n\tenvsCache.store(GlobalFlags.ConfigURL, name, vars, project, envs[name])\n\tswitch {\n\tcase name == \"\":\n\t\t// If no env was selected,\n\t\t// return only the project.\n\t\treturn project, nil, nil\n\tcase len(envs[name]) == 0:\n\t\treturn nil, nil, fmt.Errorf(\"env %q not defined in config file\", name)\n\tdefault:\n\t\treturn project, envs[name], nil\n\t}\n}\n\ntype (\n\tenvCacheK struct {\n\t\tpath, env, vars string\n\t}\n\tenvCacheV struct {\n\t\tp *Project\n\t\te []*Env\n\t}\n\tenvCache struct {\n\t\tsync.RWMutex\n\t\tm map[envCacheK]envCacheV\n\t}\n)\n\nvar envsCache = &envCache{m: make(map[envCacheK]envCacheV)}\n\nfunc (c *envCache) load(path, env string, vars Vars) (*Project, []*Env, bool) {\n\tc.RLock()\n\tv, ok := c.m[envCacheK{path: path, env: env, vars: vars.String()}]\n\tc.RUnlock()\n\treturn v.p, v.e, ok\n}\n\nfunc (c *envCache) store(path, env string, vars Vars, p *Project, e []*Env) {\n\tc.Lock()\n\tc.m[envCacheK{path: path, env: env, vars: vars.String()}] = envCacheV{p: p, e: e}\n\tc.Unlock()\n}\n\nconst (\n\tblockEnv          = \"env\"\n\trefAtlas          = \"atlas\"\n\tdefaultConfigPath = \"file://atlas.hcl\"\n)\n\nfunc parseConfig(ctx context.Context, path, env string, vars map[string]cty.Value) (*Project, error) {\n\tpr, err := partialParse(path, env)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbase, err := filepath.Abs(filepath.Dir(path))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcloud := &cmdext.AtlasConfig{\n\t\tProject: cloudapi.DefaultProjectName,\n\t}\n\tstate := schemahcl.New(\n\t\tappend(\n\t\t\tappend(cmdext.SpecOptions, specOptions...),\n\t\t\tcloud.InitBlock(),\n\t\t\tschemahcl.WithContext(ctx),\n\t\t\tschemahcl.WithScopedEnums(\"env.migration.format\", cmdmigrate.Formats...),\n\t\t\tschemahcl.WithScopedEnums(\"env.migration.exec_order\", \"LINEAR\", \"LINEAR_SKIP\", \"NON_LINEAR\"),\n\t\t\tschemahcl.WithScopedEnums(\"env.lint.review\", ReviewModes...),\n\t\t\tschemahcl.WithScopedEnums(\"lint.review\", ReviewModes...),\n\t\t\tschemahcl.WithVariables(map[string]cty.Value{\n\t\t\t\trefAtlas: cty.ObjectVal(map[string]cty.Value{\n\t\t\t\t\tblockEnv: cty.StringVal(env),\n\t\t\t\t}),\n\t\t\t}),\n\t\t\tschemahcl.WithFunctions(map[string]function.Function{\n\t\t\t\t\"file\":    schemahcl.MakeFileFunc(base),\n\t\t\t\t\"glob\":    schemahcl.MakeGlobFunc(base),\n\t\t\t\t\"fileset\": schemahcl.MakeFileSetFunc(base),\n\t\t\t\t\"getenv\":  getEnvFunc,\n\t\t\t}),\n\t\t)...,\n\t)\n\tp := &Project{Lint: &Lint{}, Diff: &Diff{}, cloud: cloud}\n\tif err := state.Eval(pr, p, vars); err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, e := range p.Envs {\n\t\te.config, e.cloud = p, cloud\n\t}\n\treturn p, nil\n}\n\nfunc init() {\n\tcloudapi.SetVersion(version, flavor)\n\tschemahcl.Register(blockEnv, &Env{})\n}\n\nfunc partialParse(path, env string) (*hclparse.Parser, error) {\n\tparser := hclparse.NewParser()\n\tfi, err := parser.ParseHCLFile(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar labeled, nonlabeled, used []*hclsyntax.Block\n\tfor _, b := range fi.Body.(*hclsyntax.Body).Blocks {\n\t\tswitch b.Type {\n\t\tcase blockEnv:\n\t\t\tswitch n := len(b.Labels); {\n\t\t\t// No env was selected.\n\t\t\tcase env == \"\" && n == 0:\n\t\t\t// Exact env was selected.\n\t\t\tcase n == 1 && b.Labels[0] == env:\n\t\t\t\tlabeled = append(labeled, b)\n\t\t\t// Dynamic env selection.\n\t\t\tcase n == 0 && b.Body != nil && b.Body.Attributes[schemahcl.AttrName] != nil:\n\t\t\t\tx := b.Body.Attributes[schemahcl.AttrName].Expr\n\t\t\t\tif x != nil && schemahcl.UseTraversal(x, hcl.Traversal{\n\t\t\t\t\thcl.TraverseRoot{Name: refAtlas},\n\t\t\t\t\thcl.TraverseAttr{Name: blockEnv},\n\t\t\t\t}) {\n\t\t\t\t\tnonlabeled = append(nonlabeled, b)\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tused = append(used, b)\n\t\t}\n\t}\n\t// Labeled blocks take precedence\n\t// over non-labeled env blocks.\n\tswitch {\n\tcase len(labeled) > 0:\n\t\tused = append(used, labeled...)\n\tcase len(nonlabeled) > 0:\n\t\tused = append(used, nonlabeled...)\n\t}\n\tfi.Body = &hclsyntax.Body{\n\t\tBlocks:     used,\n\t\tAttributes: fi.Body.(*hclsyntax.Body).Attributes,\n\t}\n\treturn parser, nil\n}\n\n// Review modes for 'schema apply'.\nconst (\n\tReviewAlways  = \"ALWAYS\"  // Always review changes. The default mode.\n\tReviewWarning = \"WARNING\" // Review changes only if there are any diagnostics (including warnings).\n\tReviewError   = \"ERROR\"   // Review changes only if there are severe diagnostics (error level).\n)\n\nvar ReviewModes = []string{ReviewAlways, ReviewWarning, ReviewError}\n\n// getEnvFunc is a custom HCL function that returns\n// the value of an environment variable.\nvar getEnvFunc = function.New(&function.Spec{\n\tParams: []function.Parameter{\n\t\t{\n\t\t\tName: \"key\",\n\t\t\tType: cty.String,\n\t\t},\n\t},\n\tType: function.StaticReturnType(cty.String),\n\tImpl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {\n\t\treturn cty.StringVal(os.Getenv(args[0].AsString())), nil\n\t},\n})\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/project_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdapi\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cloudapi\"\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdext\"\n\tcmdmigrate \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\nfunc TestEnvByName(t *testing.T) {\n\td := t.TempDir()\n\trequire.NoError(t, os.WriteFile(filepath.Join(d, \"local.txt\"), []byte(\"text\"), 0600))\n\th := `\nvariable \"name\" {\n  type = string\n  default = \"hello\"\n}\n\nlocals {\n  envName = atlas.env\n  emptyEnv = getenv(\"NOT_SET\")\n  opened = file(\"local.txt\")\n}\n\nlint {\n  review = ERROR\n  destructive {\n    error = true\n  }\n  // Backwards compatibility with old attribute.\n  log = <<EOS\n{{- range $f := .Files }}\n\t{{- $f.Name }}\n{{- end }}\nEOS\n}\n\ndiff {\n  skip {\n    drop_schema = true\n  }\n}\n\ntest {\n  schema {\n    src = [\"schema.test.hcl\"]\n    vars = {\n      a = \"1\"\n    }\n  }\n  migrate {\n    src = [\"migrate.test.hcl\"]\n    vars = {\n      b = \"2\"\n    }\n  }\n}\n\nenv \"local\" {\n  url = \"mysql://root:pass@localhost:3306/\"\n  dev = \"docker://mysql/8\"\n  src = \"${local.envName}/app.hcl\"\n  schemas = [\"hello\", \"world\"]\n  migration {\n    dir = \"file://migrations\"\n    format = atlas\n    lock_timeout = \"1s\"\n    revisions_schema = \"revisions\"\n    exec_order = LINEAR_SKIP\n  }\n  lint {\n    latest = 1\n    review = WARNING\n  }\n  diff {\n    skip {\n      drop_column = true\n    }\n  }\n  test {\n    schema {\n      src = [\"env.schema.test.hcl\"]\n      vars = {\n        a = \"a\"\n      }\n    }\n    migrate {\n      src = [\"env.migrate.test.hcl\"]\n      vars = {\n        b = \"b\"\n      }\n    }\n  }\n  bool = true\n  integer = 42\n  str = var.name\n  token  = getenv(\"ATLAS_TOKEN\")\n  token2  = getenv(\"ATLAS_TOKEN2\")\n}\n\nenv \"multi\" {\n  url = \"mysql://root:pass@localhost:3306/\"\n  src = [\n    \"./a.hcl\",\n    \"./b.hcl\",\n  ]\n  lint {\n    git {\n      dir  = \"./path\"\n      base = \"master\"\n    }\n    naming {\n      match = \"^[A-Z]+$\"\n    }\n  }\n}\n`\n\tpath := filepath.Join(d, \"atlas.hcl\")\n\terr := os.WriteFile(path, []byte(h), 0600)\n\trequire.NoError(t, err)\n\tGlobalFlags.ConfigURL = \"file://\" + path\n\trequire.NoError(t, os.Setenv(\"ATLAS_TOKEN\", \"token_atlas\"))\n\tt.Cleanup(func() { require.NoError(t, os.Unsetenv(\"ATLAS_TOKEN\")) })\n\tt.Run(\"ok\", func(t *testing.T) {\n\t\t_, envs, err := EnvByName(&cobra.Command{}, \"local\", map[string]cty.Value{\n\t\t\t\"unused\": cty.StringVal(\"value\"),\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, envs, 1)\n\t\tenv := envs[0]\n\t\tsort.Slice(env.Extra.Attrs, func(i, j int) bool {\n\t\t\treturn env.Extra.Attrs[i].K < env.Extra.Attrs[j].K\n\t\t})\n\t\trequire.NotNil(t, env.config)\n\t\tenv.config = nil\n\t\trequire.EqualValues(t, &Env{\n\t\t\tName:    \"local\",\n\t\t\tURL:     \"mysql://root:pass@localhost:3306/\",\n\t\t\tDevURL:  \"docker://mysql/8\",\n\t\t\tSchemas: []string{\"hello\", \"world\"},\n\t\t\tMigration: &Migration{\n\t\t\t\tDir:             \"file://migrations\",\n\t\t\t\tFormat:          cmdmigrate.FormatAtlas,\n\t\t\t\tLockTimeout:     \"1s\",\n\t\t\t\tRevisionsSchema: \"revisions\",\n\t\t\t\tExecOrder:       \"LINEAR_SKIP\",\n\t\t\t},\n\t\t\tDiff: &Diff{\n\t\t\t\tSkipChanges: &SkipChanges{\n\t\t\t\t\tDropColumn: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tLint: &Lint{\n\t\t\t\tLatest: 1,\n\t\t\t\tReview: ReviewWarning,\n\t\t\t\tFormat: \"{{- range $f := .Files }}\\n\\t{{- $f.Name }}\\n{{- end }}\\n\",\n\t\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\t\tChildren: []*schemahcl.Resource{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tType: \"destructive\",\n\t\t\t\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\t\t\t\tschemahcl.BoolAttr(\"error\", true),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tTest: &Test{\n\t\t\t\tSchema: struct {\n\t\t\t\t\tSrc  []string `spec:\"src\"`\n\t\t\t\t\tVars Vars     `spec:\"vars\"`\n\t\t\t\t}{\n\t\t\t\t\tSrc: []string{\"env.schema.test.hcl\"},\n\t\t\t\t\tVars: Vars{\n\t\t\t\t\t\t\"a\": cty.StringVal(\"a\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMigrate: struct {\n\t\t\t\t\tSrc  []string `spec:\"src\"`\n\t\t\t\t\tVars Vars     `spec:\"vars\"`\n\t\t\t\t}{\n\t\t\t\t\tSrc: []string{\"env.migrate.test.hcl\"},\n\t\t\t\t\tVars: Vars{\n\t\t\t\t\t\t\"b\": cty.StringVal(\"b\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\tschemahcl.BoolAttr(\"bool\", true),\n\t\t\t\t\t\tschemahcl.IntAttr(\"integer\", 42),\n\t\t\t\t\t\tschemahcl.StringAttr(\"src\", \"local/app.hcl\"),\n\t\t\t\t\t\tschemahcl.StringAttr(\"str\", \"hello\"),\n\t\t\t\t\t\tschemahcl.StringAttr(\"token\", \"token_atlas\"),\n\t\t\t\t\t\tschemahcl.StringAttr(\"token2\", \"\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tcloud: &cmdext.AtlasConfig{\n\t\t\t\tProject: cloudapi.DefaultProjectName,\n\t\t\t},\n\t\t}, env)\n\t\tsources, err := env.Sources()\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, []string{\"local/app.hcl\"}, sources)\n\n\t\tv, err := env.VarFromURL(\"env://dev\")\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"docker://mysql/8\", v)\n\t\tv, err = env.VarFromURL(\"env://src\")\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"local/app.hcl\", v)\n\t\tv, err = env.VarFromURL(\"env://migration.dir\")\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"file://migrations\", v)\n\n\t\t// Multiple sources.\n\t\tenv.DefaultExtension.Extra.SetAttr(schemahcl.StringsAttr(\"src\", \"local/app.hcl\", \"local/app.hcl\"))\n\t\tsources, err = env.Sources()\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, []string{\"local/app.hcl\", \"local/app.hcl\"}, sources)\n\t\t_, err = env.VarFromURL(\"env://src\")\n\t\trequire.Error(t, err)\n\t})\n\tt.Run(\"multi\", func(t *testing.T) {\n\t\t_, envs, err := EnvByName(&cobra.Command{}, \"multi\", nil)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, envs, 1)\n\t\tsrcs, err := envs[0].Sources()\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, []string{\"./a.hcl\", \"./b.hcl\"}, srcs)\n\t\trequire.EqualValues(t, ReviewError, envs[0].Lint.Review)\n\t\trequire.Len(t, envs[0].Lint.Extra.Children, 1)\n\t\trequire.Equal(t, \"naming\", envs[0].Lint.Extra.Children[0].Type)\n\t\trequire.Equal(t, \"1\", envs[0].Test.Schema.Vars[\"a\"].AsString())\n\t\trequire.Equal(t, \"2\", envs[0].Test.Migrate.Vars[\"b\"].AsString())\n\t})\n\tt.Run(\"with input\", func(t *testing.T) {\n\t\t_, envs, err := EnvByName(&cobra.Command{}, \"local\", map[string]cty.Value{\n\t\t\t\"name\": cty.StringVal(\"goodbye\"),\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, envs, 1)\n\t\tstr, ok := envs[0].Attr(\"str\")\n\t\trequire.True(t, ok)\n\t\tval, err := str.String()\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, \"goodbye\", val)\n\t})\n\tt.Run(\"wrong env\", func(t *testing.T) {\n\t\t_, _, err = EnvByName(&cobra.Command{}, \"home\", nil)\n\t\trequire.EqualError(t, err, `env \"home\" not defined in config file`)\n\t})\n\tt.Run(\"wrong dir\", func(t *testing.T) {\n\t\tGlobalFlags.ConfigURL = defaultConfigPath\n\t\t_, _, err = EnvByName(&cobra.Command{}, \"home\", nil)\n\t\trequire.ErrorContains(t, err, `no such file or directory`)\n\t})\n}\n\nfunc TestUnnamedEnv(t *testing.T) {\n\th := `\nenv {\n  name = atlas.env\n  log {\n    schema {\n      apply = \"env: ${atlas.env}\"\n    }\n  }\n}`\n\tpath := filepath.Join(t.TempDir(), \"atlas.hcl\")\n\terr := os.WriteFile(path, []byte(h), 0600)\n\trequire.NoError(t, err)\n\tGlobalFlags.ConfigURL = \"file://\" + path\n\t_, envs, err := EnvByName(&cobra.Command{}, \"local\", nil)\n\trequire.NoError(t, err)\n\trequire.Len(t, envs, 1)\n\trequire.Equal(t, \"local\", envs[0].Name)\n\trequire.Equal(t, \"env: local\", envs[0].Format.Schema.Apply)\n}\n\nfunc TestEnvCache(t *testing.T) {\n\th := `\nvariable \"path\" {\n  type = string\n}\n\ndata \"template_dir\" \"name\" {\n  path = var.path\n}\n\nenv {\n  name = atlas.env\n  migration {\n    dir = data.template_dir.name.url\n  }\n}\n`\n\tpath := filepath.Join(t.TempDir(), \"atlas.hcl\")\n\terr := os.WriteFile(path, []byte(h), 0600)\n\trequire.NoError(t, err)\n\tGlobalFlags.ConfigURL = \"file://\" + path\n\n\tdir := filepath.Join(t.TempDir(), \"migrations\")\n\trequire.NoError(t, os.Mkdir(dir, 0700))\n\tvars := map[string]cty.Value{\"path\": cty.StringVal(dir)}\n\n\tcmd := &cobra.Command{}\n\tcmd.SetContext(context.Background())\n\t_, envs1, err := EnvByName(cmd, \"local\", vars)\n\trequire.NoError(t, err)\n\trequire.Len(t, envs1, 1)\n\trequire.Contains(t, envs1[0].Migration.Dir, dir)\n\n\trequire.NoError(t, os.Remove(dir))\n\t_, envs1, err = EnvByName(cmd, \"local\", vars)\n\trequire.NoError(t, err)\n\trequire.Len(t, envs1, 1)\n\trequire.Contains(t, envs1[0].Migration.Dir, dir, \"should return the same dir, even if it doesn't exist anymore\")\n}\n\nfunc TestNoEnv(t *testing.T) {\n\th := `\nenv \"dev\" {\n  log {\n    schema {\n      apply = \"env: ${atlas.env}\"\n    }\n  }\n}\n\nenv {\n  name = atlas.env\n  log {\n    schema {\n      apply = \"env: ${atlas.env}\"\n    }\n  }\n}\n\nlint {\n  latest = 1\n  review = WARNING\n}\n\ndiff {\n  skip {\n    drop_column = true\n  }\n}\n`\n\tpath := filepath.Join(t.TempDir(), \"atlas.hcl\")\n\terr := os.WriteFile(path, []byte(h), 0600)\n\trequire.NoError(t, err)\n\tGlobalFlags.ConfigURL = \"file://\" + path\n\tproject, envs, err := EnvByName(&cobra.Command{}, \"\", nil)\n\trequire.NoError(t, err)\n\trequire.Len(t, envs, 0)\n\trequire.Equal(t, 1, project.Lint.Latest)\n\trequire.NotNil(t, project.Diff.SkipChanges)\n\trequire.True(t, project.Diff.SkipChanges.DropColumn)\n\trequire.Equal(t, ReviewWarning, project.Lint.Review)\n\n\tGlobalFlags.ConfigURL = path\n\t_, _, err = EnvByName(&cobra.Command{}, \"\", nil)\n\trequire.EqualError(t, err, fmt.Sprintf(\"missing scheme for config file. Did you mean file://%s?\", path))\n\n\tGlobalFlags.ConfigURL = \"boring://\" + path\n\t_, _, err = EnvByName(&cobra.Command{}, \"\", nil)\n\trequire.EqualError(t, err, `unsupported config file driver \"boring\"`)\n}\n\nfunc TestPartialParse(t *testing.T) {\n\th := `\ndata \"remote_dir\" \"ignored\" {\n  name = \"ignored\"\n}\n\nlocals {\n  a = \"b\"\n}\n\nenv {\n  name = atlas.env\n  log {\n    schema {\n      diff  = local.a\n      apply = \"env: ${atlas.env}\"\n    }\n  }\n  a = local.a\n}\n\nenv \"dev\" {\n  a = local.a\n}`\n\tpath := filepath.Join(t.TempDir(), \"atlas.hcl\")\n\terr := os.WriteFile(path, []byte(h), 0600)\n\trequire.NoError(t, err)\n\tGlobalFlags.ConfigURL = \"file://\" + path\n\t_, envs, err := EnvByName(&cobra.Command{}, \"unnamed\", nil)\n\trequire.NoError(t, err)\n\trequire.Len(t, envs, 1)\n\trequire.Equal(t, \"unnamed\", envs[0].Name)\n\trequire.Equal(t, \"b\", envs[0].Format.Schema.Diff)\n\trequire.Equal(t, \"env: unnamed\", envs[0].Format.Schema.Apply)\n\t_, envs, err = EnvByName(&cobra.Command{}, \"dev\", nil)\n\trequire.NoError(t, err)\n\trequire.Len(t, envs, 1)\n\tattr, ok := envs[0].Extra.Attr(\"a\")\n\trequire.True(t, ok)\n\tv, err := attr.String()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"b\", v)\n\n\th = `\ndata \"template_dir\" \"unknown\" {\n  path = \"unknown\"\n}\n\nenv {\n  name = atlas.env\n  a = data.template_dir.unknown.url\n}\n\nenv \"dev\" {\n  a = \"b\"\n}`\n\trequire.NoError(t, os.WriteFile(path, []byte(h), 0600))\n\t_, envs, err = EnvByName(&cobra.Command{}, \"dev\", nil)\n\trequire.NoError(t, err)\n\trequire.Len(t, envs, 1)\n\tattr, ok = envs[0].Extra.Attr(\"a\")\n\trequire.True(t, ok)\n\tv, err = attr.String()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"b\", v)\n\n\t// Loading template directory should fail.\n\t_, envs, err = EnvByName(&cobra.Command{}, \"other\", nil)\n\trequire.Error(t, err)\n\trequire.Empty(t, envs)\n\n\th = `\nenv {\n  name = contains([\"dev\", \"prod\", \"staging\"], atlas.env) ? atlas.env : \"dev\"\n}\n`\n\trequire.NoError(t, os.WriteFile(path, []byte(h), 0600))\n\t_, envs, err = EnvByName(&cobra.Command{}, \"none\", nil)\n\trequire.EqualError(t, err, `env \"none\" not defined in config file`)\n\trequire.Empty(t, envs)\n\n\th = `\nenv {\n  name = contains([\"dev\"], atlas.env) ? atlas.env : null\n}\n`\n\trequire.NoError(t, os.WriteFile(path, []byte(h), 0600))\n\t_, envs, err = EnvByName(&cobra.Command{}, \"a8m\", nil)\n\trequire.ErrorContains(t, err, \"all envs must have names on file\")\n}\n\nfunc TestDiff_Options(t *testing.T) {\n\td := &Diff{}\n\trequire.Len(t, d.Options(), 1)\n\td.SkipChanges = &SkipChanges{}\n\trequire.Len(t, d.Options(), 1)\n\n\td.SkipChanges = &SkipChanges{DropSchema: true}\n\trequire.Len(t, d.Options(), 2)\n\topts := schema.NewDiffOptions(d.Options()...)\n\trequire.True(t, opts.Skipped(&schema.DropSchema{}))\n\trequire.False(t, opts.Skipped(&schema.DropTable{}))\n\n\td.SkipChanges = &SkipChanges{DropSchema: true, DropTable: true}\n\trequire.Len(t, d.Options(), 2)\n\topts = schema.NewDiffOptions(d.Options()...)\n\trequire.True(t, opts.Skipped(&schema.DropSchema{}))\n\trequire.True(t, opts.Skipped(&schema.DropTable{}))\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/schema.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdapi\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdext\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/1lann/promptui\"\n\t\"github.com/chzyer/readline\"\n\t\"github.com/hashicorp/hcl/v2/hclwrite\"\n\t\"github.com/spf13/cobra\"\n)\n\n// schemaCmd represents the subcommand 'atlas schema'.\nfunc schemaCmd() *cobra.Command {\n\tcmd := &cobra.Command{\n\t\tUse:   \"schema\",\n\t\tShort: \"Work with atlas schemas.\",\n\t\tLong:  \"The `atlas schema` command groups subcommands working with declarative Atlas schemas.\",\n\t}\n\taddGlobalFlags(cmd.PersistentFlags())\n\treturn cmd\n}\n\ntype schemaApplyFlags struct {\n\turl         string        // URL of database to apply the changes on.\n\tdevURL      string        // URL of the dev database.\n\tpaths       []string      // Paths to HCL files.\n\ttoURLs      []string      // URLs of the desired state.\n\tplanURL     string        // URL to a pre-planned migration.\n\tschemas     []string      // Schemas to take into account when diffing.\n\texclude     []string      // List of glob patterns used to filter resources from applying (see schema.InspectOptions).\n\tinclude     []string      // List of glob patterns used to include (only) resources in applying.\n\tdryRun      bool          // Only show SQL on screen instead of applying it.\n\tedit        bool          // Open the generated SQL in an editor.\n\tautoApprove bool          // Don't prompt for approval before applying SQL.\n\tlogFormat   string        // Log format.\n\ttxMode      string        // (none, file)\n\tlockTimeout time.Duration // Lock timeout.\n}\n\n// check that the flags are valid before running the command.\nfunc (f *schemaApplyFlags) check(env *Env) error {\n\tswitch {\n\tcase f.url == \"\":\n\t\treturn errors.New(`required flag(s) \"url\" not set`)\n\tcase len(f.paths) == 0 && len(f.toURLs) == 0:\n\t\tif f.planURL != \"\" {\n\t\t\treturn errors.New(`the flag \"to\" is required to verify the provided plan`)\n\t\t}\n\t\treturn errors.New(`one of flag(s) \"file\" or \"to\" is required`)\n\tcase f.txMode != txModeNone && f.txMode != txModeFile:\n\t\treturn fmt.Errorf(\"unknown tx-mode %q\", f.txMode)\n\tcase f.autoApprove && env.Lint.Review != \"\":\n\t\treturn fmt.Errorf(\"auto-approve is not allowed when a lint policy is set to %q\", env.Lint.Review)\n\tcase f.edit && f.devURL == \"\":\n\t\treturn errors.New(\"--edit requires a connection to the dev-database (provided by --dev-url)\")\n\t}\n\t// If the old -f flag is given convert them to the URL format. If both are given,\n\t// cobra would throw an error since they are marked as mutually exclusive.\n\tif len(f.toURLs) == 0 {\n\t\tf.toURLs = fixFileURLs(f.paths)\n\t}\n\treturn nil\n}\n\n// schemaApplyCmd represents the 'atlas schema apply' subcommand.\nfunc schemaApplyCmd() *cobra.Command {\n\tvar (\n\t\tflags schemaApplyFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"apply\",\n\t\t\tShort: \"Apply an atlas schema to a target database.\",\n\t\t\t// Use 80-columns as max width.\n\t\t\tLong: `'atlas schema apply' plans and executes a database migration to bring a given\ndatabase to the state described in the provided Atlas schema. Before running the\nmigration, Atlas will print the migration plan and prompt the user for approval.\n\nThe schema is provided by one or more URLs (to a HCL file or \ndirectory, database or migration directory) using the \"--to, -t\" flag:\n  atlas schema apply -u URL --to \"file://file1.hcl\" --to \"file://file2.hcl\"\n  atlas schema apply -u URL --to \"file://schema/\" --to \"file://override.hcl\"\n\nAs a convenience, schema URLs may also be provided via an environment definition in\nthe project file (see: https://atlasgo.io/cli/projects).\n\nIf run with the \"--dry-run\" flag, atlas will exit after printing out the planned\nmigration.`,\n\t\t\tExample: `  atlas schema apply -u \"mysql://user:pass@localhost/dbname\" --to \"file://atlas.hcl\"\n  atlas schema apply -u \"mysql://localhost\" --to \"file://schema.sql\" --dev-url \"docker://mysql/8/dev\"\n  atlas schema apply --env local --dev-url \"docker://postgres/15/dev?search_path=public\" --dry-run\n  atlas schema apply -u \"sqlite://file.db\" --to \"file://schema.sql\" --dev-url \"sqlite://dev?mode=memory\"`,\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\treturn schemaApplyRunE(cmd, args, &flags)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagURL(cmd.Flags(), &flags.url)\n\taddFlagToURLs(cmd.Flags(), &flags.toURLs)\n\taddFlagExclude(cmd.Flags(), &flags.exclude)\n\taddFlagInclude(cmd.Flags(), &flags.include)\n\taddFlagSchemas(cmd.Flags(), &flags.schemas)\n\taddFlagDevURL(cmd.Flags(), &flags.devURL)\n\taddFlagDryRun(cmd.Flags(), &flags.dryRun)\n\taddFlagAutoApprove(cmd.Flags(), &flags.autoApprove)\n\taddFlagLog(cmd.Flags(), &flags.logFormat)\n\taddFlagFormat(cmd.Flags(), &flags.logFormat)\n\tcmd.Flags().StringVarP(&flags.txMode, flagTxMode, \"\", txModeFile, \"set transaction mode [none, file]\")\n\tcmd.Flags().StringVarP(&flags.planURL, flagPlan, \"\", \"\", \"URL to a pre-planned migration (e.g., atlas://repo/plans/name)\")\n\tcmd.Flags().BoolVarP(&flags.edit, flagEdit, \"\", false, \"open the generated SQL in an editor\")\n\taddFlagLockTimeout(cmd.Flags(), &flags.lockTimeout)\n\t// Hidden support for the deprecated -f flag.\n\tcmd.Flags().StringSliceVarP(&flags.paths, flagFile, \"f\", nil, \"[paths...] file or directory containing HCL or SQL files\")\n\tcobra.CheckErr(cmd.Flags().MarkHidden(flagFile))\n\tcmd.MarkFlagsMutuallyExclusive(flagFile, flagTo)\n\tcmd.MarkFlagsMutuallyExclusive(flagLog, flagFormat)\n\tcmd.MarkFlagsMutuallyExclusive(flagEdit, flagPlan)\n\tcmd.MarkFlagsMutuallyExclusive(flagDryRun, flagAutoApprove)\n\treturn cmd\n}\n\nfunc applyChanges(ctx context.Context, client *sqlclient.Client, changes []schema.Change, txMode string) error {\n\topts := planOptions(client)\n\tif txMode == txModeNone {\n\t\treturn client.ApplyChanges(ctx, changes, opts...)\n\t}\n\ttx, err := client.Tx(ctx, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := tx.ApplyChanges(ctx, changes, opts...); err != nil {\n\t\t// Rollback on error but the underlying error is still\n\t\t// returned to make type-assertion in schemaApplyRun pass.\n\t\t_ = tx.Rollback()\n\t\treturn err\n\t}\n\treturn tx.Commit()\n}\n\n// planOptions returns the default options for planning declarative changes.\nfunc planOptions(c *sqlclient.Client) []migrate.PlanOption {\n\topts := []migrate.PlanOption{\n\t\tfunc(opts *migrate.PlanOptions) {\n\t\t\topts.Indent = \"  \"\n\t\t},\n\t}\n\t// In case the scope is a database schema, generate\n\t// the plan without the schema qualifier.\n\tif c.URL.Schema != \"\" {\n\t\topts = append(opts, func(opt *migrate.PlanOptions) {\n\t\t\topt.SchemaQualifier = new(string)\n\t\t})\n\t}\n\treturn opts\n}\n\ntype schemaCleanFlags struct {\n\turl         string // URL of database to apply the changes on.\n\tautoApprove bool   // Don't prompt for approval before applying SQL.\n\tlogFormat   string // Log format.\n\tdryRun      bool   // Only show SQL on screen instead of applying it.\n}\n\n// schemaCleanCmd represents the 'atlas schema clean' subcommand.\nfunc schemaCleanCmd() *cobra.Command {\n\tvar (\n\t\tflags schemaCleanFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"clean [flags]\",\n\t\t\tShort: \"Removes all objects from the connected database.\",\n\t\t\tLong: `'atlas schema clean' drops all objects in the connected database and leaves it in an empty state.\nAs a safety feature, 'atlas schema clean' will ask for confirmation before attempting to execute any SQL.`,\n\t\t\tExample: `  atlas schema clean -u \"mysql://user:pass@localhost:3306/dbname\"\n  atlas schema clean -u \"mysql://user:pass@localhost:3306/\"`,\n\t\t\tPreRunE: func(cmd *cobra.Command, _ []string) error {\n\t\t\t\treturn schemaFlagsFromConfig(cmd)\n\t\t\t},\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\treturn schemaCleanRun(cmd, args, flags)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagURL(cmd.Flags(), &flags.url)\n\taddFlagDryRun(cmd.Flags(), &flags.dryRun)\n\taddFlagFormat(cmd.Flags(), &flags.logFormat)\n\taddFlagAutoApprove(cmd.Flags(), &flags.autoApprove)\n\tcobra.CheckErr(cmd.MarkFlagRequired(flagURL))\n\treturn cmd\n}\n\nfunc schemaCleanRun(cmd *cobra.Command, _ []string, flags schemaCleanFlags) error {\n\tc, err := sqlclient.Open(cmd.Context(), flags.url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer c.Close()\n\tvar drop []schema.Change\n\t// If the connection is bound to a schema, only drop the resources inside the schema.\n\tswitch c.URL.Schema {\n\tcase \"\":\n\t\tr, err := c.InspectRealm(cmd.Context(), nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdrop, err = c.RealmDiff(r, schema.NewRealm())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\tdefault:\n\t\ts, err := c.InspectSchema(cmd.Context(), c.URL.Schema, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdrop, err = c.SchemaDiff(s, schema.New(s.Name))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn applySchemaClean(cmd, c, drop, flags)\n}\n\ntype schemaDiffFlags struct {\n\tfromURL []string\n\ttoURL   []string\n\tdevURL  string\n\tschemas []string\n\texclude []string\n\tinclude []string\n\tformat  string\n}\n\n// schemaDiffCmd represents the 'atlas schema diff' subcommand.\nfunc schemaDiffCmd() *cobra.Command {\n\tcmd, _ := schemaDiffCmdWithFlags()\n\treturn cmd\n}\n\nfunc schemaDiffCmdWithFlags() (*cobra.Command, *schemaDiffFlags) {\n\tvar (\n\t\tflags schemaDiffFlags\n\t\tcmd   = &cobra.Command{\n\t\t\tUse:   \"diff\",\n\t\t\tShort: \"Calculate and print the diff between two schemas.\",\n\t\t\tLong: `'atlas schema diff' reads the state of two given schema definitions, \ncalculates the difference in their schemas, and prints a plan of\nSQL statements to migrate the \"from\" database to the schema of the \"to\" database.\nThe database states can be read from a connected database, an HCL project or a migration directory.`,\n\t\t\tExample: `  atlas schema diff --from \"mysql://user:pass@localhost:3306/test\" --to \"file://schema.hcl\"\n  atlas schema diff --from \"mysql://user:pass@localhost:3306\" --to \"file://schema_1.hcl\" --to \"file://schema_2.hcl\"\n  atlas schema diff --from \"mysql://user:pass@localhost:3306\" --to \"file://migrations\" --format '{{ sql . \"  \" }}'`,\n\t\t\tPreRunE: func(cmd *cobra.Command, _ []string) error {\n\t\t\t\treturn schemaFlagsFromConfig(cmd)\n\t\t\t},\n\t\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\t\tenv, err := selectEnv(cmd)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn schemaDiffRun(cmd, args, flags, env)\n\t\t\t}),\n\t\t}\n\t)\n\tcmd.Flags().SortFlags = false\n\taddFlagURLs(cmd.Flags(), &flags.fromURL, flagFrom, flagFromShort)\n\taddFlagToURLs(cmd.Flags(), &flags.toURL)\n\taddFlagDevURL(cmd.Flags(), &flags.devURL)\n\taddFlagSchemas(cmd.Flags(), &flags.schemas)\n\taddFlagExclude(cmd.Flags(), &flags.exclude)\n\taddFlagInclude(cmd.Flags(), &flags.include)\n\taddFlagFormat(cmd.Flags(), &flags.format)\n\tcobra.CheckErr(cmd.MarkFlagRequired(flagFrom))\n\tcobra.CheckErr(cmd.MarkFlagRequired(flagTo))\n\treturn cmd, &flags\n}\n\n// schemaFmtCmd represents the 'atlas schema fmt' subcommand.\nfunc schemaFmtCmd() *cobra.Command {\n\tcmd := &cobra.Command{\n\t\tUse:   \"fmt [path ...]\",\n\t\tShort: \"Formats Atlas HCL files\",\n\t\tLong: `'atlas schema fmt' formats all \".hcl\" files under the given paths using\ncanonical HCL layout style as defined by the github.com/hashicorp/hcl/v2/hclwrite package.\nUnless stated otherwise, the fmt command will use the current directory.\n\nAfter running, the command will print the names of the files it has formatted. If all\nfiles in the directory are formatted, no input will be printed out.\n`,\n\t\tRunE: RunE(func(cmd *cobra.Command, args []string) error {\n\t\t\treturn schemaFmtRun(cmd, args)\n\t\t}),\n\t}\n\treturn cmd\n}\n\nfunc schemaFmtRun(cmd *cobra.Command, args []string) error {\n\tif len(args) == 0 {\n\t\targs = append(args, \"./\")\n\t}\n\tfor _, path := range args {\n\t\ttasks, err := tasks(path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, task := range tasks {\n\t\t\tchanged, err := fmtFile(task)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif changed {\n\t\t\t\tcmd.Println(task.path)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// selectEnv returns the Env from the current project file based on the selected\n// argument. If selected is \"\", or no project file exists in the current directory\n// a zero-value Env is returned.\nfunc selectEnv(cmd *cobra.Command) (*Env, error) {\n\tswitch name := GlobalFlags.SelectedEnv; {\n\t// A config file was passed without an env.\n\tcase name == \"\" && cmd.Flags().Changed(flagConfig):\n\t\tp, envs, err := EnvByName(cmd, name, GlobalFlags.Vars)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif len(envs) != 0 {\n\t\t\treturn nil, fmt.Errorf(\"unexpected number of envs found: %d\", len(envs))\n\t\t}\n\t\treturn &Env{Lint: p.Lint, Diff: p.Diff, Migration: &Migration{}, config: p}, nil\n\t// No config nor env was passed.\n\tcase name == \"\":\n\t\treturn &Env{Lint: &Lint{}, Migration: &Migration{}}, nil\n\t// Env was passed.\n\tdefault:\n\t\t_, envs, err := EnvByName(cmd, name, GlobalFlags.Vars)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif len(envs) > 1 {\n\t\t\treturn nil, fmt.Errorf(\"multiple envs found for %q\", name)\n\t\t}\n\t\treturn envs[0], nil\n\t}\n}\n\nfunc schemaFlagsFromConfig(cmd *cobra.Command) error {\n\tenv, err := selectEnv(cmd)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn setSchemaEnvFlags(cmd, env)\n}\n\nfunc setSchemaEnvFlags(cmd *cobra.Command, env *Env) error {\n\tif err := maySetFlag(cmd, flagDevURL, env.DevURL); err != nil {\n\t\treturn err\n\t}\n\tsrcs, err := env.Sources()\n\tif err != nil {\n\t\treturn err\n\t}\n\tsrcs = fixFileURLs(srcs)\n\tif err := maySetFlag(cmd, flagFile, strings.Join(srcs, \",\")); err != nil {\n\t\treturn err\n\t}\n\tif err := maySetFlag(cmd, flagSchema, strings.Join(env.Schemas, \",\")); err != nil {\n\t\treturn err\n\t}\n\tif err := maySetFlag(cmd, flagExclude, strings.Join(env.Exclude, \",\")); err != nil {\n\t\treturn err\n\t}\n\tif err := maySetFlag(cmd, flagInclude, strings.Join(env.Include, \",\")); err != nil {\n\t\treturn err\n\t}\n\tswitch cmd.Name() {\n\tcase \"clean\":\n\t\tif err := maySetFlag(cmd, flagURL, env.URL); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagFormat, env.Format.Schema.Clean); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase \"inspect\":\n\t\tif err := maySetFlag(cmd, flagURL, env.URL); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagFormat, env.Format.Schema.Inspect); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase \"apply\":\n\t\tif err := maySetFlag(cmd, flagURL, env.URL); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagFormat, env.Format.Schema.Apply); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase \"diff\":\n\t\tif err := maySetFlag(cmd, flagFormat, env.Format.Schema.Diff); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase \"push\":\n\t\tif err := maySetFlag(cmd, flagURL, strings.Join(srcs, \",\")); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := maySetFlag(cmd, flagFormat, env.Format.Schema.Push); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase \"test\":\n\t\t// Give the \"src\" precedence over the \"url\" argument.\n\t\tif len(srcs) > 0 {\n\t\t\tif err := maySetFlag(cmd, flagURL, strings.Join(srcs, \",\")); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if err := maySetFlag(cmd, flagURL, env.URL); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// diff holds the changes between two realms.\ntype diff struct {\n\tfrom, to *schema.Realm\n\tchanges  []schema.Change\n}\n\nfunc computeDiff(ctx context.Context, differ *sqlclient.Client, from, to *cmdext.StateReadCloser, opts ...schema.DiffOption) (*diff, error) {\n\tcurrent, err := from.ReadState(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdesired, err := to.ReadState(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar changes []schema.Change\n\tswitch {\n\t// In case an HCL file is compared against a specific database schema (not a realm).\n\tcase to.HCL && len(desired.Schemas) == 1 && from.Schema != \"\" && desired.Schemas[0].Name != from.Schema:\n\t\treturn nil, fmt.Errorf(\"mismatched HCL and database schemas: %q <> %q\", from.Schema, desired.Schemas[0].Name)\n\t// Compare realm if the desired state is an HCL file or both connections are not bound to a schema.\n\tcase from.HCL, to.HCL, from.Schema == \"\" && to.Schema == \"\":\n\t\tchanges, err = differ.RealmDiff(current, desired, opts...)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase from.Schema == \"\" && to.Schema != \"\":\n\t\treturn nil, fmt.Errorf(\"cannot diff a schema %q with a database connection. See: https://atlasgo.io/url\", to.Schema)\n\tcase from.Schema != \"\" && to.Schema == \"\":\n\t\treturn nil, fmt.Errorf(\"cannot diff a database connection with a schema %q. See: https://atlasgo.io/url\", from.Schema)\n\tdefault:\n\t\t// SchemaDiff checks for name equality which is irrelevant in the case\n\t\t// the user wants to compare their contents, reset them to allow the comparison.\n\t\tcurrent.Schemas[0].Name, desired.Schemas[0].Name = \"\", \"\"\n\t\tchanges, err = differ.SchemaDiff(current.Schemas[0], desired.Schemas[0], opts...)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn &diff{\n\t\tchanges: changes,\n\t\tfrom:    current,\n\t\tto:      desired,\n\t}, nil\n}\n\nconst (\n\tanswerApply = \"Apply\"\n\tanswerAbort = \"Abort\"\n)\n\n// cmdPrompt returns a promptui.Select that uses the given command's input and output.\nfunc cmdPrompt(cmd *cobra.Command) *promptui.Select {\n\treturn &promptui.Select{\n\t\tLabel:    \"Are you sure?\",\n\t\tHideHelp: true,\n\t\tStdin:    io.NopCloser(cmd.InOrStdin()),\n\t\tStdout:   nopBellCloser{cmd.OutOrStdout()},\n\t}\n}\n\nfunc promptUser(cmd *cobra.Command) bool {\n\tprompt := cmdPrompt(cmd)\n\tprompt.Items = []string{answerApply, answerAbort}\n\t_, result, err := prompt.Run()\n\tif err != nil && !errors.Is(err, promptui.ErrInterrupt) {\n\t\t// Fail in case of unexpected errors.\n\t\tcobra.CheckErr(err)\n\t}\n\treturn result == answerApply\n}\n\ntype nopBellCloser struct{ io.Writer }\n\nfunc (n nopBellCloser) Write(p []byte) (int, error) {\n\tif len(p) == 1 && p[0] == readline.CharBell {\n\t\treturn 0, nil // Skip bell noise.\n\t}\n\treturn n.Writer.Write(p)\n}\n\nfunc (nopBellCloser) Close() error { return nil }\n\nfunc tasks(path string) ([]fmttask, error) {\n\tvar tasks []fmttask\n\tstat, err := os.Stat(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !stat.IsDir() {\n\t\tif strings.HasSuffix(path, \".hcl\") {\n\t\t\ttasks = append(tasks, fmttask{\n\t\t\t\tpath: path,\n\t\t\t\tinfo: stat,\n\t\t\t})\n\t\t}\n\t\treturn tasks, nil\n\t}\n\tall, err := os.ReadDir(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, f := range all {\n\t\tif f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\tif strings.HasSuffix(f.Name(), \".hcl\") {\n\t\t\ti, err := f.Info()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ttasks = append(tasks, fmttask{\n\t\t\t\tpath: filepath.Join(path, f.Name()),\n\t\t\t\tinfo: i,\n\t\t\t})\n\t\t}\n\t}\n\treturn tasks, nil\n}\n\ntype fmttask struct {\n\tpath string\n\tinfo fs.FileInfo\n}\n\n// fmtFile tries to format a file and reports if formatting occurred.\nfunc fmtFile(task fmttask) (bool, error) {\n\torig, err := os.ReadFile(task.path)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tformatted := hclwrite.Format(orig)\n\tif !bytes.Equal(formatted, orig) {\n\t\treturn true, os.WriteFile(task.path, formatted, task.info.Mode())\n\t}\n\treturn false, nil\n}\n\n// fixFileURLs converts all file paths to a URL format, if not already.\n// For example, \"schema.hcl\" to \"file://schema.hcl\".\nfunc fixFileURLs(src []string) []string {\n\tfor i, s := range src {\n\t\tif !isURL(s) {\n\t\t\tsrc[i] = \"file://\" + s\n\t\t}\n\t}\n\treturn src\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/schema_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdapi\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdlog\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst (\n\tunformatted = `block  \"x\"  {\n x = 1\n    y     = 2\n}\n`\n\tformatted = `block \"x\" {\n  x = 1\n  y = 2\n}\n`\n)\n\nfunc TestSchema_Diff(t *testing.T) {\n\t// Creates the missing table.\n\ts, err := runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", openSQLite(t, \"\"),\n\t\t\"--to\", openSQLite(t, \"create table t1 (id int);\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"-- Create \\\"t1\\\" table\\nCREATE TABLE `t1` (`id` int NULL);\\n\", s)\n\n\t// Format indentation one table.\n\ts, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", openSQLite(t, \"\"),\n\t\t\"--to\", openSQLite(t, \"create table t1 (id int);\"),\n\t\t\"--format\", `{{ sql . \"  \" }}`,\n\t)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"-- Create \\\"t1\\\" table\\nCREATE TABLE `t1` (\\n  `id` int NULL\\n);\\n\", s)\n\n\t// No changes.\n\ts, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", openSQLite(t, \"\"),\n\t\t\"--to\", openSQLite(t, \"\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"Schemas are synced, no changes to be made.\\n\", s)\n\n\t// Format no changes.\n\ts, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", openSQLite(t, \"\"),\n\t\t\"--to\", openSQLite(t, \"\"),\n\t\t\"--format\", `{{ sql . \" \" }}`,\n\t)\n\trequire.NoError(t, err)\n\trequire.Empty(t, s)\n\n\t// Desired state from migration directory requires dev database.\n\t_, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", \"file://testdata/sqlite\",\n\t\t\"--to\", openSQLite(t, \"\"),\n\t)\n\trequire.EqualError(t, err, \"--dev-url cannot be empty. See: https://atlasgo.io/atlas-schema/sql#dev-database\")\n\n\t// Desired state from migration directory.\n\ts, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", openSQLite(t, \"\"),\n\t\t\"--to\", \"file://testdata/sqlite\",\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"-- Create \\\"tbl\\\" table\\nCREATE TABLE `tbl` (`col` int NOT NULL, `col_2` bigint NULL);\\n\", s)\n\n\t// Desired state from migration directory.\n\ts, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", openSQLite(t, \"\"),\n\t\t\"--to\", \"file://testdata/sqlite\",\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"-- Create \\\"tbl\\\" table\\nCREATE TABLE `tbl` (`col` int NOT NULL, `col_2` bigint NULL);\\n\", s)\n\n\t// Current state from migration directory, desired state from HCL - synced.\n\tp := filepath.Join(t.TempDir(), \"schema.hcl\")\n\trequire.NoError(t, os.WriteFile(p, []byte(`schema \"main\" {}\ntable \"tbl\" {\n  schema = schema.main\n  column \"col\" {\n    type = int\n  }\n  column \"col_2\" {\n    type = bigint\n    null = true\n  }\n}`), 0644))\n\ts, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", \"file://testdata/sqlite\",\n\t\t\"--to\", \"file://\"+p,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"Schemas are synced, no changes to be made.\\n\", s)\n\n\t// Current state from migration directory, desired state from HCL - missing column.\n\tp = filepath.Join(t.TempDir(), \"schema.hcl\")\n\trequire.NoError(t, os.WriteFile(p, []byte(`schema \"main\" {}\ntable \"tbl\" {\n  schema = schema.main\n  column \"col\" {\n    type = int\n  }\n  column \"col_2\" {\n    type = bigint\n    null = true\n  }\n  column \"col_3\" {\n    type = text\n  }\n}`), 0644))\n\ts, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", \"file://testdata/sqlite\",\n\t\t\"--to\", \"file://\"+p,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.EqualValues(\n\t\tt,\n\t\t\"-- Add column \\\"col_3\\\" to table: \\\"tbl\\\"\\nALTER TABLE `tbl` ADD COLUMN `col_3` text NOT NULL;\\n\",\n\t\ts,\n\t)\n\n\t// Current state from migration directory with version, desired state from HCL - two missing columns.\n\ts, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", \"file://testdata/sqlite?version=20220318104614\",\n\t\t\"--to\", \"file://\"+p,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.EqualValues(\n\t\tt,\n\t\t\"-- Add column \\\"col_2\\\" to table: \\\"tbl\\\"\\n\"+\n\t\t\t\"ALTER TABLE `tbl` ADD COLUMN `col_2` bigint NULL;\\n\"+\n\t\t\t\"-- Add column \\\"col_3\\\" to table: \\\"tbl\\\"\\n\"+\n\t\t\t\"ALTER TABLE `tbl` ADD COLUMN `col_3` text NOT NULL;\\n\",\n\t\ts,\n\t)\n\n\t// Current state from migration directory, desired state from multi file HCL - missing column.\n\tp = t.TempDir()\n\tvar (\n\t\tone = filepath.Join(p, \"one.hcl\")\n\t\ttwo = filepath.Join(p, \"two.hcl\")\n\t)\n\trequire.NoError(t, os.WriteFile(one, []byte(`table \"tbl\" {\n  schema = schema.main\n  column \"col\" {\n    type = int\n  }\n  column \"col_2\" {\n    type = bigint\n    null = true\n  }\n  column \"col_3\" {\n    type = text\n  }\n}`), 0644))\n\trequire.NoError(t, os.WriteFile(two, []byte(`schema \"main\" {}`), 0644))\n\ts, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", \"file://testdata/sqlite\",\n\t\t\"--to\", \"file://\"+p,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.EqualValues(\n\t\tt,\n\t\t\"-- Add column \\\"col_3\\\" to table: \\\"tbl\\\"\\nALTER TABLE `tbl` ADD COLUMN `col_3` text NOT NULL;\\n\",\n\t\ts,\n\t)\n\ts, err = runCmd(\n\t\tschemaDiffCmd(),\n\t\t\"--from\", \"file://testdata/sqlite\",\n\t\t\"--to\", \"file://\"+one,\n\t\t\"--to\", \"file://\"+two,\n\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.EqualValues(\n\t\tt,\n\t\t\"-- Add column \\\"col_3\\\" to table: \\\"tbl\\\"\\nALTER TABLE `tbl` ADD COLUMN `col_3` text NOT NULL;\\n\",\n\t\ts,\n\t)\n\n\tt.Run(\"FromConfig\", func(t *testing.T) {\n\t\tvar (\n\t\t\tp   = t.TempDir()\n\t\t\tcp  = filepath.Join(p, \"atlas.hcl\")\n\t\t\tsp  = filepath.Join(p, \"schema.hcl\")\n\t\t\tcfg = fmt.Sprintf(`\nenv \"local\" {\n  dev = \"%s\"\n  format {\n    schema {\n      diff = \"{{ sql . \\\"\\t\\\" }}\"\n    }\n  }\n}`, openSQLite(t, \"\"))\n\t\t)\n\t\trequire.NoError(t, os.WriteFile(cp, []byte(cfg), 0600))\n\t\trequire.NoError(t, os.WriteFile(sp, []byte(`\nschema \"main\" {}\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n  }\n}\n`), 0600))\n\n\t\tcmd := schemaCmd()\n\t\tcmd.AddCommand(schemaDiffCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"diff\",\n\t\t\t\"-c\", \"file://\"+cp,\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--to\", \"file://\"+sp,\n\t\t\t\"--from\", openSQLite(t, \"\"),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"-- Create \\\"users\\\" table\\nCREATE TABLE `users` (\\n\\t`id` int NOT NULL\\n);\\n\", s)\n\t})\n\n\tt.Run(\"SkipChanges\", func(t *testing.T) {\n\t\tvar (\n\t\t\tp   = t.TempDir()\n\t\t\tcfg = filepath.Join(p, \"atlas.hcl\")\n\t\t)\n\t\terr = os.WriteFile(cfg, []byte(`\nvariable \"destructive\" {\n  type = bool\n  default = false\n}\n\nenv \"local\" {\n  diff {\n    skip {\n      drop_table = !var.destructive\n    }\n  }\n}\n`), 0600)\n\t\trequire.NoError(t, err)\n\n\t\t// Skip destructive changes.\n\t\tcmd := schemaCmd()\n\t\tcmd.AddCommand(schemaDiffCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"diff\",\n\t\t\t\"-c\", \"file://\"+cfg,\n\t\t\t\"--from\", openSQLite(t, \"create table users (id int);\"),\n\t\t\t\"--to\", openSQLite(t, \"\"),\n\t\t\t\"--env\", \"local\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"Schemas are synced, no changes to be made.\\n\", s)\n\n\t\t// Apply destructive changes.\n\t\tcmd = schemaCmd()\n\t\tcmd.AddCommand(schemaDiffCmd())\n\t\ts, err = runCmd(\n\t\t\tcmd, \"diff\",\n\t\t\t\"-c\", \"file://\"+cfg,\n\t\t\t\"--from\", openSQLite(t, \"create table users (id int);\"),\n\t\t\t\"--to\", openSQLite(t, \"\"),\n\t\t\t\"--env\", \"local\",\n\t\t\t\"--var\", \"destructive=true\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\tlines := strings.Split(strings.TrimSpace(s), \"\\n\")\n\t\trequire.Equal(t, []string{\n\t\t\t\"-- Disable the enforcement of foreign-keys constraints\",\n\t\t\t\"PRAGMA foreign_keys = off;\",\n\t\t\t`-- Drop \"users\" table`,\n\t\t\t\"DROP TABLE `users`;\",\n\t\t\t\"-- Enable back the enforcement of foreign-keys constraints\",\n\t\t\t\"PRAGMA foreign_keys = on;\",\n\t\t}, lines)\n\t})\n\n\tt.Run(\"FromConfig/DevURL\", func(t *testing.T) {\n\t\tvar (\n\t\t\tp    = t.TempDir()\n\t\t\tcfg  = filepath.Join(p, \"atlas.hcl\")\n\t\t\tfrom = filepath.Join(p, \"schema1.sql\")\n\t\t)\n\t\terr = os.WriteFile(cfg, []byte(`\nenv \"local\" {\n  dev = \"sqlite://dev?mode=memory&_fk=1\"\n  exclude = [\"posts\"]\n}\n`), 0600)\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, os.WriteFile(from, []byte(`CREATE TABLE users (id int);`), 0600))\n\t\tcmd := schemaCmd()\n\t\tcmd.AddCommand(schemaDiffCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"diff\",\n\t\t\t\"--from\", \"file://\"+from,\n\t\t\t\"--to\", openSQLite(t, \"CREATE TABLE users (id int, name text); CREATE TABLE posts (id int);\"),\n\t\t\t\"--config\", \"file://\"+cfg,\n\t\t\t\"--env\", \"local\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"-- Add column \\\"name\\\" to table: \\\"users\\\"\\nALTER TABLE `users` ADD COLUMN `name` text NULL;\\n\", s)\n\t})\n\n\tt.Run(\"CompareDataSrc\", func(t *testing.T) {\n\t\tvar (\n\t\t\tp        = t.TempDir()\n\t\t\tcfg      = filepath.Join(p, \"atlas.hcl\")\n\t\t\tfrom, to = filepath.Join(p, \"schema_from.hcl\"), filepath.Join(p, \"schema_to.hcl\")\n\t\t)\n\t\terr = os.WriteFile(cfg, []byte(`\nvariable \"from_path\" {\n  type = string\n}\nvariable \"to_path\" {\n  type = string\n}\ndata \"hcl_schema\" \"from\" {\n  path = var.from_path\n}\ndata \"hcl_schema\" \"to\" {\n  path = var.to_path\n}\nenv \"drift\" {\n  dev = \"sqlite://dev?mode=memory&_fk=1\"\n  # Variables defined and available with env:// prefix.\n  from_schema = data.hcl_schema.from.url\n  to_schema   = data.hcl_schema.to.url\n}\n`), 0600)\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, os.WriteFile(from, []byte(`\nschema \"main\" {}\ntable \"t1\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n  }\n}`), 0600))\n\t\trequire.NoError(t, os.WriteFile(to, []byte(`\nschema \"main\" {}\ntable \"t2\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n  }\n}`), 0600))\n\n\t\tcmd := schemaCmd()\n\t\tcmd.AddCommand(schemaDiffCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"diff\",\n\t\t\t\"--config\", \"file://\"+cfg,\n\t\t\t\"--env\", \"drift\",\n\t\t\t\"--var\", \"from_path=\"+from,\n\t\t\t\"--var\", \"to_path=\"+to,\n\t\t\t\"--from\", \"env://from_schema\",\n\t\t\t\"--to\", \"env://to_schema\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, []string{\n\t\t\t\"-- Disable the enforcement of foreign-keys constraints\",\n\t\t\t\"PRAGMA foreign_keys = off;\",\n\t\t\t`-- Drop \"t1\" table`,\n\t\t\t\"DROP TABLE `t1`;\",\n\t\t\t`-- Create \"t2\" table`,\n\t\t\t\"CREATE TABLE `t2` (`id` int NOT NULL);\",\n\t\t\t\"-- Enable back the enforcement of foreign-keys constraints\",\n\t\t\t\"PRAGMA foreign_keys = on;\",\n\t\t}, strings.Split(strings.TrimSpace(s), \"\\n\"))\n\t})\n\tt.Run(\"InspectDataSrc\", func(t *testing.T) {\n\t\tvar (\n\t\t\tp   = t.TempDir()\n\t\t\tcfg = filepath.Join(p, \"atlas.hcl\")\n\t\t\tapp = filepath.Join(p, \"schema.hcl\")\n\t\t)\n\t\terr = os.WriteFile(cfg, []byte(`\nvariable \"path\" {\n  type = string\n}\ndata \"hcl_schema\" \"app\" {\n  path = var.path\n}\nenv \"app\" {\n  dev = \"sqlite://dev?mode=memory&_fk=1\"\n  # Variables defined and available with env:// prefix.\n  app = data.hcl_schema.app.url\n}\n`), 0600)\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, os.WriteFile(app, []byte(`\nschema \"main\" {}\ntable \"t1\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n  }\n}`), 0600))\n\n\t\tcmd := schemaCmd()\n\t\tcmd.AddCommand(schemaInspectCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"inspect\",\n\t\t\t\"--config\", \"file://\"+cfg,\n\t\t\t\"--env\", \"app\",\n\t\t\t\"--var\", \"path=\"+app,\n\t\t\t\"--url\", \"env://app\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, `table \"t1\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nschema \"main\" {\n}\n`, s)\n\t})\n}\n\nfunc TestSchema_Apply(t *testing.T) {\n\tconst drvName = \"checknormalizer\"\n\t// If no dev-database is given, there must not be a call to Driver.Normalize.\n\tsqlclient.Register(\n\t\tdrvName,\n\t\tsqlclient.OpenerFunc(func(ctx context.Context, url *url.URL) (*sqlclient.Client, error) {\n\t\t\turl.Scheme = \"sqlite\"\n\t\t\tc, err := sqlclient.OpenURL(ctx, url)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tc.Driver = &assertNormalizerDriver{t: t, Driver: c.Driver}\n\t\t\treturn c, nil\n\t\t}),\n\t)\n\n\tp := filepath.Join(t.TempDir(), \"schema.hcl\")\n\trequire.NoError(t, os.WriteFile(p, []byte(`schema \"my_schema\" {}`), 0644))\n\t_, _ = runCmd(\n\t\tschemaApplyCmd(),\n\t\t\"--url\", drvName+\"://?mode=memory\",\n\t\t\"-f\", p,\n\t)\n}\n\nfunc TestSchema_ApplyLog(t *testing.T) {\n\tt.Run(\"DryRun\", func(t *testing.T) {\n\t\tdb := openSQLite(t, \"\")\n\t\tcmd := schemaCmd()\n\t\tcmd.AddCommand(schemaApplyCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-u\", db,\n\t\t\t\"--to\", openSQLite(t, \"\"),\n\t\t\t\"--dry-run\",\n\t\t\t\"--format\", \"{{ json .Changes }}\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"{}\", s)\n\n\t\tcmd = schemaCmd()\n\t\tcmd.AddCommand(schemaApplyCmd())\n\t\ts, err = runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-u\", db,\n\t\t\t\"--to\", openSQLite(t, \"create table t1 (id int);\"),\n\t\t\t\"--dry-run\",\n\t\t\t\"--format\", \"{{ json .Changes }}\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(\n\t\t\tt, \"{\\\"Pending\\\":[\\\"CREATE TABLE `t1` (\\\\n  `id` int NULL\\\\n)\\\"]}\",\n\t\t\tstrings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t\t)\n\t})\n\n\tt.Run(\"AutoApprove\", func(t *testing.T) {\n\t\tdb := openSQLite(t, \"\")\n\t\tcmd := schemaCmd()\n\t\tcmd.AddCommand(schemaApplyCmd())\n\t\ts, err := runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-u\", db,\n\t\t\t\"--to\", openSQLite(t, \"create table t1 (id int);\"),\n\t\t\t\"--auto-approve\",\n\t\t\t\"--format\", \"{{ json .Changes }}\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(\n\t\t\tt, \"{\\\"Applied\\\":[\\\"CREATE TABLE `t1` (\\\\n  `id` int NULL\\\\n)\\\"]}\",\n\t\t\tstrings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t\t)\n\n\t\tcmd = schemaCmd()\n\t\tcmd.AddCommand(schemaApplyCmd())\n\t\ts, err = runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-u\", db,\n\t\t\t\"--to\", openSQLite(t, \"create table t1 (id int);\"),\n\t\t\t\"--auto-approve\",\n\t\t\t\"--format\", \"{{ json .Changes }}\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"{}\", s)\n\n\t\tcmd = schemaCmd()\n\t\tcmd.AddCommand(schemaApplyCmd())\n\t\ts, err = runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-u\", db,\n\t\t\t\"--to\", openSQLite(t, \"create table t2 (id int);\"),\n\t\t\t\"--auto-approve\",\n\t\t\t\"--format\", \"{{ json .Changes }}\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(\n\t\t\tt, \"{\\\"Applied\\\":[\\\"PRAGMA foreign_keys = off\\\",\\\"DROP TABLE `t1`\\\",\\\"CREATE TABLE `t2` (\\\\n  `id` int NULL\\\\n)\\\",\\\"PRAGMA foreign_keys = on\\\"]}\",\n\t\t\tstrings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t\t)\n\n\t\t// Simulate a failed execution.\n\t\tconn, err := sql.Open(\"sqlite3\", strings.TrimPrefix(db, \"sqlite://\"))\n\t\trequire.NoError(t, err)\n\t\t_, err = conn.Exec(\"INSERT INTO t2 (`id`) VALUES (1), (1)\")\n\t\trequire.NoError(t, err)\n\n\t\tcmd = schemaCmd()\n\t\tcmd.AddCommand(schemaApplyCmd())\n\t\ts, err = runCmd(\n\t\t\tcmd, \"apply\",\n\t\t\t\"-u\", db,\n\t\t\t\"--to\", openSQLite(t, \"create table t2 (id int, c int);create unique index t2_id on t2 (id);\"),\n\t\t\t\"--auto-approve\",\n\t\t\t\"--format\", \"{{ json .Changes }}\\n\",\n\t\t)\n\t\trequire.ErrorContains(t, err, `UNIQUE constraint failed: t2.id`)\n\t\tvar out struct {\n\t\t\tApplied []string\n\t\t\tPending []string\n\t\t\tError   cmdlog.StmtError\n\t\t}\n\t\trequire.NoError(t, json.NewDecoder(strings.NewReader(s)).Decode(&out))\n\t\trequire.Len(t, out.Applied, 1)\n\t\trequire.Len(t, out.Pending, 1)\n\t\trequire.Equal(t, \"ALTER TABLE `t2` ADD COLUMN `c` int NULL\", strings.TrimRight(out.Applied[0], \";\"))\n\t\trequire.Equal(t, \"CREATE UNIQUE INDEX `t2_id` ON `t2` (`id`)\", strings.TrimRight(out.Pending[0], \";\"))\n\t\trequire.Equal(t, out.Pending[0], out.Error.Stmt)\n\t\trequire.Contains(t, out.Error.Text, `UNIQUE constraint failed: t2.id`)\n\t})\n}\n\nfunc TestSchema_ApplySchemaMismatch(t *testing.T) {\n\tvar (\n\t\tp   = t.TempDir()\n\t\tsrc = filepath.Join(p, \"schema.hcl\")\n\t)\n\t// SQLite always has a schema called \"main\".\n\terr := os.WriteFile(src, []byte(`\nschema \"hello\" {}\n`), 0600)\n\trequire.NoError(t, err)\n\tcmd := schemaCmd()\n\tcmd.AddCommand(schemaApplyCmd())\n\t_, err = runCmd(\n\t\tcmd, \"apply\",\n\t\t\"-u\", openSQLite(t, \"\"),\n\t\t\"-f\", src,\n\t)\n\trequire.EqualError(t, err, `mismatched HCL and database schemas: \"main\" <> \"hello\"`)\n}\n\nfunc TestSchema_ApplySkip(t *testing.T) {\n\tvar (\n\t\tp   = t.TempDir()\n\t\tcfg = filepath.Join(p, \"atlas.hcl\")\n\t\tsrc = filepath.Join(p, \"schema.hcl\")\n\t)\n\terr := os.WriteFile(src, []byte(`\nschema \"main\" {}\n\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n  }\n}\n`), 0600)\n\trequire.NoError(t, err)\n\terr = os.WriteFile(cfg, []byte(`\nvariable \"schema\" {\n  type = string\n  default = \"dev\"\n}\n\nvariable \"destructive\" {\n  type = bool\n  default = false\n}\n\nenv \"local\" {\n  src = var.schema\n  dev_url = \"sqlite://dev?mode=memory&_fk=1\"\n}\n\ndiff {\n  skip {\n    drop_table = !var.destructive\n  }\n}\n`), 0600)\n\trequire.NoError(t, err)\n\n\t// Skip destructive changes.\n\tcmd := schemaCmd()\n\tcmd.AddCommand(schemaApplyCmd())\n\ts, err := runCmd(\n\t\tcmd, \"apply\",\n\t\t\"-u\", openSQLite(t, \"create table pets (id int);\"),\n\t\t\"-c\", \"file://\"+cfg,\n\t\t\"--var\", \"schema=file://\"+src,\n\t\t\"--env\", \"local\",\n\t\t\"--auto-approve\",\n\t\t\"--format\", \"{{ json .Changes }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(\n\t\tt, \"{\\\"Applied\\\":[\\\"CREATE TABLE `users` (\\\\n  `id` int NOT NULL\\\\n)\\\"]}\",\n\t\tstrings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t)\n\n\t// Skip destructive changes by using project-level policy (no --env was passed).\n\tcmd = schemaCmd()\n\tcmd.AddCommand(schemaApplyCmd())\n\ts, err = runCmd(\n\t\tcmd, \"apply\",\n\t\t\"-u\", openSQLite(t, \"create table pets (id int);\"),\n\t\t\"-c\", \"file://\"+cfg, // Using the project-level policy.\n\t\t\"--to\", \"file://\"+src,\n\t\t\"--dev-url\", \"sqlite://dev?mode=memory&_fk=1\",\n\t\t\"--auto-approve\",\n\t\t\"--format\", \"{{ json .Changes }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(\n\t\tt, \"{\\\"Applied\\\":[\\\"CREATE TABLE `users` (\\\\n  `id` int NOT NULL\\\\n)\\\"]}\",\n\t\tstrings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t)\n\n\t// Apply destructive changes.\n\tcmd = schemaCmd()\n\tcmd.AddCommand(schemaApplyCmd())\n\ts, err = runCmd(\n\t\tcmd, \"apply\",\n\t\t\"-u\", openSQLite(t, \"create table pets (id int);\"),\n\t\t\"-c\", \"file://\"+cfg,\n\t\t\"--var\", \"schema=file://\"+src,\n\t\t\"--var\", \"destructive=true\",\n\t\t\"--env\", \"local\",\n\t\t\"--auto-approve\",\n\t\t\"--format\", \"{{ json .Changes }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(\n\t\tt, \"{\\\"Applied\\\":[\\\"PRAGMA foreign_keys = off\\\",\\\"DROP TABLE `pets`\\\",\\\"CREATE TABLE `users` (\\\\n  `id` int NOT NULL\\\\n)\\\",\\\"PRAGMA foreign_keys = on\\\"]}\",\n\t\tstrings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t)\n}\n\nfunc TestSchema_ApplySources(t *testing.T) {\n\tvar (\n\t\tp   = t.TempDir()\n\t\tcfg = filepath.Join(p, \"atlas.hcl\")\n\t\tsrc = []string{filepath.Join(p, \"one.hcl\"), filepath.Join(p, \"two.hcl\")}\n\t)\n\terr := os.WriteFile(src[0], []byte(`\nschema \"main\" {}\n\ntable \"one\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n  }\n}\n`), 0600)\n\trequire.NoError(t, err)\n\terr = os.WriteFile(src[1], []byte(`\ntable \"two\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n  }\n}\n`), 0600)\n\trequire.NoError(t, err)\n\terr = os.WriteFile(cfg, []byte(fmt.Sprintf(`\nenv \"local\" {\n  src = [%q, %q]\n}`, src[0], src[1])), 0600)\n\trequire.NoError(t, err)\n\n\tcmd := schemaCmd()\n\tcmd.AddCommand(schemaApplyCmd())\n\ts, err := runCmd(\n\t\tcmd, \"apply\",\n\t\t\"-u\", openSQLite(t, \"\"),\n\t\t\"-c\", \"file://\"+cfg,\n\t\t\"--env\", \"local\",\n\t\t\"--auto-approve\",\n\t\t\"--format\", \"{{ json .Changes }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(\n\t\tt, \"{\\\"Applied\\\":[\\\"CREATE TABLE `one` (\\\\n  `id` int NOT NULL\\\\n)\\\",\\\"CREATE TABLE `two` (\\\\n  `id` int NOT NULL\\\\n)\\\"]}\",\n\t\tstrings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t)\n}\n\nfunc TestSchema_ToFlagPrecedence(t *testing.T) {\n\tvar (\n\t\tp       = t.TempDir()\n\t\tcfg     = filepath.Join(p, \"atlas.hcl\")\n\t\thclFile = filepath.Join(p, \"schema.hcl\")\n\t\tsqlFile = filepath.Join(p, \"schema.sql\")\n\t)\n\terr := os.WriteFile(hclFile, []byte(`\nschema \"main\" {}\n\ntable \"one\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n  }\n}\n`), 0600)\n\trequire.NoError(t, err)\n\terr = os.WriteFile(sqlFile, []byte(\"create table tbl (col integer)\"), 0600)\n\trequire.NoError(t, err)\n\terr = os.WriteFile(cfg, []byte(fmt.Sprintf(`\nenv \"local\" {\n  src = \"file://%s\"\n}`, sqlFile)), 0600)\n\trequire.NoError(t, err)\n\n\tcmd := schemaCmd()\n\tcmd.AddCommand(schemaApplyCmd())\n\ts, err := runCmd(\n\t\tcmd, \"apply\",\n\t\t\"-u\", openSQLite(t, \"\"),\n\t\t\"-c\", \"file://\"+cfg,\n\t\t\"--to\", \"file://\"+hclFile,\n\t\t\"--env\", \"local\",\n\t\t\"--auto-approve\",\n\t\t\"--format\", \"{{ json .Changes }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(\n\t\tt, \"{\\\"Applied\\\":[\\\"CREATE TABLE `one` (\\\\n  `id` int NOT NULL\\\\n)\\\"]}\",\n\t\tstrings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t)\n}\n\nfunc TestSchema_ApplySQL(t *testing.T) {\n\tt.Run(\"File\", func(t *testing.T) {\n\t\tdb := openSQLite(t, \"\")\n\t\tp := filepath.Join(t.TempDir(), \"schema.sql\")\n\t\trequire.NoError(t, os.WriteFile(p, []byte(`create table t1 (id int NOT NULL);`), 0600))\n\t\ts, err := runCmd(\n\t\t\tschemaApplyCmd(),\n\t\t\t\"-u\", db,\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", \"file://\"+p,\n\t\t\t\"--auto-approve\",\n\t\t\t\"--format\", \"{{ json .Changes }}\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(\n\t\t\tt, \"{\\\"Applied\\\":[\\\"CREATE TABLE `t1` (\\\\n  `id` int NOT NULL\\\\n)\\\"]}\",\n\t\t\tstrings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t\t)\n\n\t\ts, err = runCmd(\n\t\t\tschemaApplyCmd(),\n\t\t\t\"-u\", db,\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", \"file://\"+p,\n\t\t\t\"--auto-approve\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"Schema is synced, no changes to be made\\n\", s)\n\t})\n\tt.Run(\"Dir\", func(t *testing.T) {\n\t\tdb := openSQLite(t, \"\")\n\t\ts, err := runCmd(\n\t\t\tschemaApplyCmd(),\n\t\t\t\"-u\", db,\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", \"file://testdata/sqlite\",\n\t\t\t\"--auto-approve\",\n\t\t\t\"--format\", \"{{ json .Changes }}\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(\n\t\t\tt, \"{\\\"Applied\\\":[\\\"CREATE TABLE `tbl` (\\\\n  `col` int NOT NULL,\\\\n  `col_2` bigint NULL\\\\n)\\\"]}\",\n\t\t\tstrings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t\t)\n\n\t\ts, err = runCmd(\n\t\t\tschemaApplyCmd(),\n\t\t\t\"-u\", db,\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", \"file://testdata/sqlite\",\n\t\t\t\"--auto-approve\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"Schema is synced, no changes to be made\\n\", s)\n\t})\n\tt.Run(\"Error\", func(t *testing.T) {\n\t\t_, err := runCmd(\n\t\t\tschemaApplyCmd(),\n\t\t\t\"-u\", openSQLite(t, \"\"),\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", \"file://testdata/sqlite\",\n\t\t\t\"--to\", \"file://testdata/sqlite2\",\n\t\t)\n\t\trequire.Error(t, err)\n\n\t\t_, err = runCmd(\n\t\t\tschemaApplyCmd(),\n\t\t\t\"-u\", openSQLite(t, \"\"),\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", \"file://\"+t.TempDir(),\n\t\t)\n\t\trequire.ErrorContains(t, err, `contains neither SQL nor HCL files`)\n\n\t\tp := t.TempDir()\n\t\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"schema.sql\"), []byte(`create table t1 (id int NOT NULL);`), 0600))\n\t\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"schema.hcl\"), []byte(`schema \"main\" {}`), 0600))\n\t\t_, err = runCmd(\n\t\t\tschemaApplyCmd(),\n\t\t\t\"-u\", openSQLite(t, \"\"),\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", \"file://\"+p,\n\t\t)\n\t\trequire.EqualError(t, err, `ambiguous schema: both SQL and HCL files found: \"schema.hcl\", \"schema.sql\"`)\n\n\t\t_, err = runCmd(\n\t\t\tschemaApplyCmd(),\n\t\t\t\"-u\", openSQLite(t, \"\"),\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", \"testdata/sqlite\",\n\t\t)\n\t\trequire.EqualError(t, err, \"missing scheme. Did you mean file://testdata/sqlite?\")\n\t})\n\tt.Run(\"TxMode\", func(t *testing.T) {\n\t\tdb := openSQLite(t, \"\")\n\t\tp := filepath.Join(t.TempDir(), \"schema.hcl\")\n\t\trequire.NoError(t, os.WriteFile(p, []byte(`schema \"main\" {}\n\ntable \"ok\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n  }\n}\n\ntable \"bad\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n    default = \"invalid check\"\n  }\n}`), 0600))\n\t\ts, err := runCmd(\n\t\t\tschemaApplyCmd(),\n\t\t\t\"-u\", db,\n\t\t\t\"--to\", \"file://\"+p,\n\t\t\t\"--auto-approve\",\n\t\t\t\"--format\", \"{{ json .Changes }}\",\n\t\t)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(\n\t\t\tt, strings.ReplaceAll(s, \";\", \"\"), // Compatibility between ent/oss.\n\t\t\t\"{\\\"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)\\\",\",\n\t\t)\n\t\trequire.Regexp(t, `Error: .* near \"\\)\": syntax error`, s)\n\n\t\t// The \"ok\" table should be created, as changes are rolled back on error.\n\t\ts, err = runCmd(schemaInspectCmd(), \"-u\", db)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"schema \\\"main\\\" {\\n}\\n\", s)\n\t})\n}\n\nfunc TestSchema_ApplyReview(t *testing.T) {\n\tt.Run(\"mutex-auto-approve\", func(t *testing.T) {\n\t\tcfg := filepath.Join(t.TempDir(), \"atlas.hcl\")\n\t\trequire.NoError(t, os.WriteFile(cfg, []byte(`env \"test\" {\n  lint {\n    review = WARNING\n  }\n}`), 0600))\n\t\tdb := openSQLite(t, \"\")\n\t\tp := filepath.Join(t.TempDir(), \"schema.sql\")\n\t\trequire.NoError(t, os.WriteFile(p, []byte(`create table t1 (id int NOT NULL);`), 0600))\n\t\tcmd := schemaCmd()\n\t\tcmd.AddCommand(schemaApplyCmd())\n\t\t_, err := runCmd(\n\t\t\tcmd,\n\t\t\t\"apply\",\n\t\t\t\"-c\", \"file://\"+cfg,\n\t\t\t\"--url\", db,\n\t\t\t\"--env\", \"test\",\n\t\t\t\"--dev-url\", openSQLite(t, \"\"),\n\t\t\t\"--to\", \"file://\"+p,\n\t\t\t\"--auto-approve\",\n\t\t)\n\t\trequire.ErrorContains(t, err, `auto-approve is not allowed when a lint policy is set to \"WARNING\"`)\n\t})\n}\n\nfunc TestSchema_InspectLog(t *testing.T) {\n\tdb := openSQLite(t, \"create table t1 (id integer primary key);create table t2 (name text);\")\n\tcmd := schemaCmd()\n\tcmd.AddCommand(schemaInspectCmd())\n\ts, err := runCmd(\n\t\tcmd, \"inspect\",\n\t\t\"-u\", db,\n\t\t\"--format\", \"{{ json . }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.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)\n}\n\nfunc TestSchema_InspectFile(t *testing.T) {\n\tvar (\n\t\tp   = t.TempDir()\n\t\tcp  = filepath.Join(p, \"atlas.hcl\")\n\t\tsp  = filepath.Join(p, \"schema.hcl\")\n\t\tcfg = fmt.Sprintf(`\nenv \"db\" {\n  url = \"%s\"\n  dev = \"docker://should-not-be-opened\"\n}\n\nenv \"file\" {\n  dev = \"%s\"\n}\n`, openSQLite(t, \"create table t1(c int)\"), openSQLite(t, \"\"))\n\t)\n\n\trequire.NoError(t, os.WriteFile(cp, []byte(cfg), 0600))\n\trequire.NoError(t, os.WriteFile(sp, []byte(`\nschema \"main\" {}\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    type = int\n  }\n}\n`), 0600))\n\tcmd := schemaCmd()\n\tcmd.AddCommand(schemaInspectCmd())\n\ts, err := runCmd(\n\t\tcmd, \"inspect\",\n\t\t\"-c\", \"file://\"+cp,\n\t\t\"--env\", \"db\",\n\t\t\"--format\", \"{{ sql . }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"-- Create \\\"t1\\\" table\\nCREATE TABLE `t1` (`c` int NULL);\\n\", s)\n\n\tcmd = schemaCmd()\n\tcmd.AddCommand(schemaInspectCmd())\n\ts, err = runCmd(\n\t\tcmd, \"inspect\",\n\t\t\"-c\", \"file://\"+cp,\n\t\t\"--env\", \"file\",\n\t\t\"--url\", \"file://\"+sp,\n\t\t\"--format\", \"{{ sql . }}\",\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"-- Create \\\"users\\\" table\\nCREATE TABLE `users` (`id` int NOT NULL);\\n\", s)\n}\n\nfunc TestFmt(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname          string\n\t\tinputDir      map[string]string\n\t\texpectedDir   map[string]string\n\t\texpectedFile  string\n\t\texpectedOut   string\n\t\targs          []string\n\t\texpectedPrint bool\n\t}{\n\t\t{\n\t\t\tname: \"specific file\",\n\t\t\tinputDir: map[string]string{\n\t\t\t\t\"test.hcl\": unformatted,\n\t\t\t},\n\t\t\texpectedDir: map[string]string{\n\t\t\t\t\"test.hcl\": formatted,\n\t\t\t},\n\t\t\targs:        []string{\"test.hcl\"},\n\t\t\texpectedOut: \"test.hcl\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"current dir\",\n\t\t\tinputDir: map[string]string{\n\t\t\t\t\"test.hcl\": unformatted,\n\t\t\t},\n\t\t\texpectedDir: map[string]string{\n\t\t\t\t\"test.hcl\": formatted,\n\t\t\t},\n\t\t\texpectedOut: \"test.hcl\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"multi path implicit\",\n\t\t\tinputDir: map[string]string{\n\t\t\t\t\"test.hcl\":  unformatted,\n\t\t\t\t\"test2.hcl\": unformatted,\n\t\t\t},\n\t\t\texpectedDir: map[string]string{\n\t\t\t\t\"test.hcl\":  formatted,\n\t\t\t\t\"test2.hcl\": formatted,\n\t\t\t},\n\t\t\texpectedOut: \"test.hcl\\ntest2.hcl\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"multi path explicit\",\n\t\t\tinputDir: map[string]string{\n\t\t\t\t\"test.hcl\":  unformatted,\n\t\t\t\t\"test2.hcl\": unformatted,\n\t\t\t},\n\t\t\texpectedDir: map[string]string{\n\t\t\t\t\"test.hcl\":  formatted,\n\t\t\t\t\"test2.hcl\": formatted,\n\t\t\t},\n\t\t\targs:        []string{\"test.hcl\", \"test2.hcl\"},\n\t\t\texpectedOut: \"test.hcl\\ntest2.hcl\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"formatted\",\n\t\t\tinputDir: map[string]string{\n\t\t\t\t\"test.hcl\": formatted,\n\t\t\t},\n\t\t\texpectedDir: map[string]string{\n\t\t\t\t\"test.hcl\": formatted,\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdir := setupFmtTest(t, tt.inputDir)\n\t\t\tout, err := runCmd(schemaFmtCmd(), tt.args...)\n\t\t\trequire.NoError(t, err)\n\t\t\tassertDir(t, dir, tt.expectedDir)\n\t\t\trequire.EqualValues(t, tt.expectedOut, out)\n\t\t})\n\t}\n}\n\nfunc TestSchema_Clean(t *testing.T) {\n\tvar (\n\t\tu      = fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", filepath.Join(t.TempDir(), \"test.db\"))\n\t\tc, err = sqlclient.Open(context.Background(), u)\n\t)\n\trequire.NoError(t, err)\n\n\t// Apply migrations onto database.\n\t_, err = runCmd(migrateApplyCmd(), \"--dir\", \"file://testdata/sqlite\", \"--url\", u)\n\trequire.NoError(t, err)\n\n\t// Run clean and expect to be clean.\n\t_, err = runCmd(migrateApplyCmd(), \"--dir\", \"file://testdata/sqlite\", \"--url\", u)\n\trequire.NoError(t, err)\n\ts, err := runCmd(schemaCleanCmd(), \"--url\", u, \"--auto-approve\")\n\trequire.NoError(t, err)\n\trequire.NotZero(t, s)\n\trequire.NoError(t, c.Driver.CheckClean(context.Background(), nil))\n}\n\nfunc assertDir(t *testing.T, dir string, expected map[string]string) {\n\tact := make(map[string]string)\n\tfiles, err := os.ReadDir(dir)\n\trequire.NoError(t, err)\n\tfor _, f := range files {\n\t\tif f.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\tcontents, err := os.ReadFile(filepath.Join(dir, f.Name()))\n\t\trequire.NoError(t, err)\n\t\tact[f.Name()] = string(contents)\n\t}\n\trequire.EqualValues(t, expected, act)\n}\n\nfunc setupFmtTest(t *testing.T, inputDir map[string]string) string {\n\twd, err := os.Getwd()\n\trequire.NoError(t, err)\n\tdir, err := os.MkdirTemp(os.TempDir(), \"fmt-test-\")\n\trequire.NoError(t, err)\n\terr = os.Chdir(dir)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\tos.RemoveAll(dir)\n\t\tos.Chdir(wd) //nolint:errcheck\n\t})\n\tfor name, contents := range inputDir {\n\t\tfile := path.Join(dir, name)\n\t\terr = os.WriteFile(file, []byte(contents), 0600)\n\t}\n\trequire.NoError(t, err)\n\treturn dir\n}\n\ntype assertNormalizerDriver struct {\n\tmigrate.Driver\n\tt *testing.T\n}\n\n// NormalizeSchema returns the normal representation of a schema.\nfunc (d *assertNormalizerDriver) NormalizeSchema(context.Context, *schema.Schema) (*schema.Schema, error) {\n\td.t.Fatal(\"did not expect a call to NormalizeSchema\")\n\treturn nil, nil\n}\n\n// NormalizeRealm returns the normal representation of a database.\nfunc (d *assertNormalizerDriver) NormalizeRealm(context.Context, *schema.Realm) (*schema.Realm, error) {\n\td.t.Fatal(\"did not expect a call to NormalizeRealm\")\n\treturn nil, nil\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/baseline1/1_baseline.sql",
    "content": "-- create \"baseline\" table\nCREATE TABLE baseline (`c` int NOT NULL);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/baseline1/atlas.sum",
    "content": "h1:GqOjMVGk2H0qYhhtJ1SPCyyHEBbWP/LD2ueWQTY4e6A=\n1_baseline.sql h1:rZgkRmNcN2UEKgxru1nHCpBRVn/fjFavyQ4xxPxhrD4=\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/baseline2/1_baseline.sql",
    "content": "-- create \"baseline\" table\nCREATE TABLE baseline (`c` int NOT NULL);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/baseline2/20220318104614_initial.sql",
    "content": "-- create \"tbl\" table\nCREATE TABLE tbl (`col` int NOT NULL);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/baseline2/20220318104615_second.sql",
    "content": "ALTER TABLE `tbl` ADD `col_2` bigint;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/baseline2/atlas.sum",
    "content": "h1:sxNQqhuqhm1fLpr3WN9N/M/niaS81Y7k5RrSaKpmBZE=\n1_baseline.sql h1:rZgkRmNcN2UEKgxru1nHCpBRVn/fjFavyQ4xxPxhrD4=\n20220318104614_initial.sql h1:/B1/+IxzgrRc4tCm1tpcpMhocHgqkdWF+iffxuguYaQ=\n20220318104615_second.sql h1:nUc1cUvm8BzjTZdbavM1IRlNpfhtyY3YyZJ8v23K9j4=\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/dbmate/1_initial.sql",
    "content": "-- migrate:up\nCREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\n\n/*\n Multiline comment ...\n */\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\n\n-- Normal comment\n-- With a second line\nINSERT INTO post (title) VALUES (\n'This is\nmy multiline\n\nvalue');\n\n-- migrate:down\n\n\nDROP TABLE post;"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/dbmate/2_second_migration.sql",
    "content": "\n\n\n-- migrate:up\n\n\n\n\nCREATE TABLE tbl_2 (col INT);"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/dbmate_gold/1_initial.sql",
    "content": "CREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\n/*\n Multiline comment ...\n */\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\n-- Normal comment\n-- With a second line\nINSERT INTO post (title) VALUES (\n'This is\nmy multiline\n\nvalue');\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/dbmate_gold/2_second_migration.sql",
    "content": "CREATE TABLE tbl_2 (col INT);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/flyway/B2__baseline.sql",
    "content": "CREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    created_at TIMESTAMP NOT NULL\n    PRIMARY KEY (id)\n);\n\nINSERT INTO post (title, created_at) VALUES (\n'This is\nmy multiline\n\nvalue', NOW());"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/flyway/R__views.sql",
    "content": "CREATE VIEW `my_view` AS SELECT * FROM `post`;"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/flyway/U1__initial.sql",
    "content": "DROP TABLE tbl;"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/flyway/V1__initial.sql",
    "content": "-- comment\nCREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\n\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\n\nINSERT INTO post (title, created_at) VALUES (\n'This is\nmy multiline\n\nvalue', NOW());\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/flyway/V2__second_migration.sql",
    "content": "\n\n\n-- migrate:up\n\n\n\n\nCREATE TABLE tbl_2 (col INT);"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/flyway/V3__third_migration.sql",
    "content": "ALTER TABLE tbl_2 ADD col_1 INTEGER NOT NULL;"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/flyway_gold/2_baseline.sql",
    "content": "CREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    created_at TIMESTAMP NOT NULL\n    PRIMARY KEY (id)\n);\nINSERT INTO post (title, created_at) VALUES (\n'This is\nmy multiline\n\nvalue', NOW());\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/flyway_gold/3R_views.sql",
    "content": "CREATE VIEW `my_view` AS SELECT * FROM `post`;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/flyway_gold/3_third_migration.sql",
    "content": "ALTER TABLE tbl_2 ADD col_1 INTEGER NOT NULL;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/golang-migrate/1_initial.down.sql",
    "content": "DROP TABLE tbl;"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/golang-migrate/1_initial.up.sql",
    "content": "CREATE TABLE tbl\n(\n    col INT\n);"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/golang-migrate/2_second_migration.down.sql",
    "content": "DROP TABLE tbl_2;"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/golang-migrate/2_second_migration.up.sql",
    "content": "CREATE TABLE tbl_2 (col INT);"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/golang-migrate_gold/1_initial.sql",
    "content": "CREATE TABLE tbl\n(\n    col INT\n);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/golang-migrate_gold/2_second_migration.sql",
    "content": "CREATE TABLE tbl_2 (col INT);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/goose/1_initial.sql",
    "content": "-- +goose Up\nCREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\n\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\n\nINSERT INTO post (title) VALUES (\n'This is\nmy multiline\n\nvalue');\n\n-- +goose Down\nDROP TABLE post;"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/goose/2_second_migration.sql",
    "content": "\n\n\n-- +goose Up\n\n\nALTER TABLE post ADD updated_at TIMESTAMP NOT NULL;\n\n-- +goose StatementBegin\n-- Comment for the function declaration.\nCREATE\nOR REPLACE FUNCTION histories_partition_creation( DATE, DATE )\nreturns void AS $$\nDECLARE\ncreate_query text;\nBEGIN\nFOR create_query IN\nSELECT 'CREATE TABLE IF NOT EXISTS histories_'\n           || TO_CHAR(d, 'YYYY_MM')\n           || ' ( CHECK( created_at >= timestamp '''\n           || TO_CHAR(d, 'YYYY-MM-DD 00:00:00')\n           || ''' AND created_at < timestamp '''\n           || TO_CHAR(d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00')\n           || ''' ) ) inherits ( histories );'\nFROM generate_series($1, $2, '1 month') AS d LOOP\n    EXECUTE create_query;\nEND LOOP;  -- LOOP END\nEND;         -- FUNCTION END\n$$\nlanguage plpgsql;\n-- +goose StatementEnd"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/goose_gold/1_initial.sql",
    "content": "CREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\nINSERT INTO post (title) VALUES (\n'This is\nmy multiline\n\nvalue');\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/goose_gold/2_second_migration.sql",
    "content": "ALTER TABLE post ADD updated_at TIMESTAMP NOT NULL;\n-- Comment for the function declaration.\nCREATE\nOR REPLACE FUNCTION histories_partition_creation( DATE, DATE )\nreturns void AS $$\nDECLARE\ncreate_query text;\nBEGIN\nFOR create_query IN\nSELECT 'CREATE TABLE IF NOT EXISTS histories_'\n           || TO_CHAR(d, 'YYYY_MM')\n           || ' ( CHECK( created_at >= timestamp '''\n           || TO_CHAR(d, 'YYYY-MM-DD 00:00:00')\n           || ''' AND created_at < timestamp '''\n           || TO_CHAR(d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00')\n           || ''' ) ) inherits ( histories );'\nFROM generate_series($1, $2, '1 month') AS d LOOP\n    EXECUTE create_query;\nEND LOOP;  -- LOOP END\nEND;         -- FUNCTION END\n$$\nlanguage plpgsql;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/liquibase/1_initial.sql",
    "content": "--liquibase formatted sql\n\n--changeset atlas:1-1\nCREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\n--rollback: DROP TABLE post;\n\n--changeset atlas:1-2\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\n--rollback: ALTER TABLE post DROP created_at;\n\n--changeset atlas:1-3\nINSERT INTO post (title) VALUES (\n'This is\nmy multiline\n\nvalue');\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/liquibase/2_second_migration.sql",
    "content": "--liquibase formatted sql\n\n--changeset atlas:2-1\nCREATE TABLE tbl_2 (col INT);\n--rollback DROP TABLE tbl_2;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/liquibase_gold/1_initial.sql",
    "content": "--changeset atlas:1-1\nCREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\n--changeset atlas:1-2\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\n--changeset atlas:1-3\nINSERT INTO post (title) VALUES (\n'This is\nmy multiline\n\nvalue');\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/import/liquibase_gold/2_second_migration.sql",
    "content": "--changeset atlas:2-1\nCREATE TABLE tbl_2 (col INT);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/mysql/20220318104614_initial.sql",
    "content": "-- add new schema named \"atlantis\"\nCREATE DATABASE `atlantis`;\n-- create \"tbl\" table\nCREATE TABLE `atlantis`.`tbl` (`col` int NOT NULL) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/mysql/20220420213403_second.sql",
    "content": "ALTER TABLE `atlantis`.`tbl` ADD `col_2` TEXT;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/mysql/atlas.sum",
    "content": "h1:EGX5/CEEerpLWqYQNHB1veTXon8t05wEGJiX2fOtFXg=\n20220318104614_initial.sql h1:EoDHPlX7fTGn5qiCdR5xhwFh+DrOi3cQ7Y49BsIy97k=\n20220420213403_second.sql h1:cAioQjDgJkOIiMAyEwqaurPs0EHpTeu0CnWlJzNj5SE=\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlite/20220318104614_initial.sql",
    "content": "-- create \"tbl\" table\nCREATE TABLE tbl (`col` int NOT NULL);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlite/20220318104615_second.sql",
    "content": "ALTER TABLE `tbl` ADD `col_2` bigint;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlite/atlas.sum",
    "content": "h1:GMi7mvWSIHv0I/Wrc2NCGVt9Z5hWZbPa6wL986t7Z2o=\n20220318104614_initial.sql h1:FifWjY2X0g2YVnb18Qm+QBPvoldDOOob7bS0LrFuCXc=\n20220318104615_second.sql h1:wbPDlODOQeixCiopAhlT7W4xOO9TgJxzjYjxf4TA2f4=\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlite2/20220318104614_initial.sql",
    "content": "-- create \"tbl\" table\nCREATE TABLE tbl (`col` int NOT NULL);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlite2/20220318104615_second.sql",
    "content": "ALTER TABLE `tbl` ADD `col_2` bigint;\nasdasd ALTER TABLE `tbl` ADD `col_3` bigint; -- will fail\nALTER TABLE `tbl` ADD `col_4` bigint;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlite2/atlas.sum",
    "content": "h1:lXdG49p5Vr5b9eARNKq3Gkgd+flbQXDM+XDyB6b2nzw=\n20220318104614_initial.sql h1:FifWjY2X0g2YVnb18Qm+QBPvoldDOOob7bS0LrFuCXc=\n20220318104615_second.sql h1:UA1TOODS2yU138E2HBlChe/O8vSmTRxkHs4OJOUK3K8=\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx/20220925092817_initial.sql",
    "content": "-- create \"users\" table\nCREATE TABLE `users` (`id` integer NOT NULL, `name` text NULL, PRIMARY KEY (`id`));\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx/20220925094021_second.sql",
    "content": "-- create \"friendships\" table\nCREATE 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);\n\nINSERT INTO `users` (`id`) VALUES (1), (2);\nINSERT INTO `friendships` (`user_id`, `friend_id`) VALUES (1,2), (2,1);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx/20220925094437_third.sql",
    "content": "-- disable the enforcement of foreign-keys constraints\nPRAGMA foreign_keys = off;\n-- create \"new_users\" table\nCREATE TABLE `new_users` (`id` integer NOT NULL, PRIMARY KEY (`id`));\n-- copy rows from old table \"users\" to new temporary table \"new_users\"\nINSERT INTO `new_users` (`id`) SELECT `id` FROM `users`;\n-- drop \"users\" table after copying rows\nDROP TABLE `users`;\n-- rename temporary table \"new_users\" to \"users\"\nALTER TABLE `new_users` RENAME TO `users`;\n-- enable back the enforcement of foreign-keys constraints\nPRAGMA foreign_keys = on;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx/atlas.sum",
    "content": "h1:09lkmQGTxdoqPwK0ZXtU4+KHipufkVp1Jlje3t6Opy4=\n20220925092817_initial.sql h1:ZGeLdeqNUMXqJm+hPkhBrhzbtUzSBH8yVTsnSnJo/qU=\n20220925094021_second.sql h1:vcoquz3yk+TlTPiQgW5hHpS/abIvySCM/bzgwYTDoqY=\n20220925094437_third.sql h1:2pbBiUBKsEC5+ppfPPTDr+iwJSgZ2rM4qmHI44/vmnc=\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx2/20220925092817_initial.sql",
    "content": "-- create \"users\" table\nCREATE TABLE `users` (`id` integer NOT NULL, `name` text NULL, PRIMARY KEY (`id`));\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx2/20220925094021_second.sql",
    "content": "-- create \"friendships\" table\nCREATE 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);\n\nINSERT INTO `users` (`id`) VALUES (1), (2);\nINSERT INTO `friendships` (`user_id`, `friend_id`) VALUES (1,2), (2,1);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx2/20220925094437_third.sql",
    "content": "-- disable the enforcement of foreign-keys constraints\nPRAGMA foreign_keys = off;\n-- create \"new_users\" table\nCREATE TABLE `new_users` (`id` integer NOT NULL, PRIMARY KEY (`id`));\n-- copy rows from old table \"users\" to new temporary table \"new_users\"\nINSERT INTO `new_users` (`id`) SELECT `id` FROM `users`;\n-- drop \"users\" table after copying rows\nDROP TABLE `users`;\n-- rename temporary table \"new_users\" to \"users\"\nALTER TABLE `new_users` RENAME TO `users`;\n-- insert faulty data\nINSERT INTO `friendships` (`user_id`, `friend_id`) VALUES (3,2);\n-- enable back the enforcement of foreign-keys constraints\nPRAGMA foreign_keys = on;\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx2/atlas.sum",
    "content": "h1:eH+7c2mVWbrhky00/3SKYklyHLyz+QzDk1UZJ9+ZJsg=\n20220925092817_initial.sql h1:ZGeLdeqNUMXqJm+hPkhBrhzbtUzSBH8yVTsnSnJo/qU=\n20220925094021_second.sql h1:vcoquz3yk+TlTPiQgW5hHpS/abIvySCM/bzgwYTDoqY=\n20220925094437_third.sql h1:58glD96PVBa0fSu8x/3Gbwbf7N6WjAcVl4jh/XcNXoM=\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx3/20220925092817_initial.sql",
    "content": "-- create \"users\" table\nCREATE TABLE `users` (`id` integer NOT NULL, `name` text NULL, PRIMARY KEY (`id`));\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx3/20220925094021_second.sql",
    "content": "-- atlas:txmode none\n\n-- Create a table.\nCREATE TABLE t1 (a INTEGER PRIMARY KEY);\n\n-- Cause migrations to fail.\nINSERT INTO t1 VALUES (1), (1);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx3/atlas.sum",
    "content": "h1:tTdOsRIKj8kX3o4eUQpw6znQsGVorkUrxi2o3C/ELL4=\n20220925092817_initial.sql h1:ZGeLdeqNUMXqJm+hPkhBrhzbtUzSBH8yVTsnSnJo/qU=\n20220925094021_second.sql h1:RTw52JCxOkWfSnY1N/kRZeLkmAFmvY2BXfZKDzhV3QM=\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx4/20220925092817_initial.sql",
    "content": "-- create \"users\" table\nCREATE TABLE `users` (`id` integer NOT NULL, `name` text NULL, PRIMARY KEY (`id`));\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx4/20220925094021_second.sql",
    "content": "-- atlas:txmode unknown\n\n-- Create a table.\nCREATE TABLE t1 (a INTEGER PRIMARY KEY);\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/sqlitetx4/atlas.sum",
    "content": "h1:RO76A3Kj66lD13e+iIb5lafWPtz4S3ypswaBm5kPRrI=\n20220925092817_initial.sql h1:ZGeLdeqNUMXqJm+hPkhBrhzbtUzSBH8yVTsnSnJo/qU=\n20220925094021_second.sql h1:MH4JwNo3hLxH0rauBusXr3IvJJFm9EC2TPe0DhXbgkE=\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/templatedir/1.sql",
    "content": "{{- if eq .Env \"dev\" }}\n    create table dev1 (c text);\n{{- else  }}\n    create table prod1 (c text);\n{{- end }}"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/templatedir/2.sql",
    "content": "{{- if eq .Env \"dev\" }}\n    create table dev2 (c text);\n    {{ template \"shared/users\" \"dev2\" }}\n{{- else  }}\n    create table prod2 (c text);\n    {{ template \"shared/users\" \"prod2\" }}\n{{- end }}"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/templatedir/atlas.sum",
    "content": "h1:qhwlEKNEXRVSUiyBXmbiSiS26un12DoxHCR3WDzrDdA=\n1.sql h1:b/5P45x6+CVoyVbBJ/BVc5Z2cI46XfoW92QH3T1kqxY=\n2.sql h1:El2EOcXWK2PfPV6yJg4hBVtc4aHheV/MFEPjho9SEmQ=\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/testdata/templatedir/shared/users.sql",
    "content": "{{- define \"shared/users\" }}\ncreate table users_{{ $ }} (c text);\n{{- end}}"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/vercheck/notification.tmpl",
    "content": "{{- with .Advisory -}}\nSECURITY ADVISORY\n{{ .Text }}\n{{- end }}\n{{- with .Latest -}}\nA new version of Atlas is available ({{ .Version }}){{ with .Link }}: {{ . }}\n{{ end }}\n{{- with .Summary }}\n{{ . }}\n{{- end }}\n{{- end }}"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/vercheck/req_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage vercheck\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cloudapi\"\n)\n\nfunc addHeaders(_ context.Context, req *http.Request) {\n\treq.Header.Set(\"User-Agent\", cloudapi.UserAgent())\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/vercheck/vercheck.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage vercheck\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdstate\"\n)\n\n// StateFileName is the name of the file where the vercheck state is stored.\nconst StateFileName = \"release.json\"\n\n// New returns a new VerChecker for the endpoint.\nfunc New(endpoint string) *VerChecker {\n\treturn &VerChecker{\n\t\tendpoint: endpoint,\n\t\tstate:    &cmdstate.File[State]{Name: StateFileName},\n\t}\n}\n\ntype (\n\t// Latest contains information about the most recent version.\n\tLatest struct {\n\t\t// Version is the new version name.\n\t\tVersion string\n\t\t// Summary contains a brief description of the new version.\n\t\tSummary string\n\t\t// Link is a URL to a web page describing the new version.\n\t\tLink string\n\t}\n\t// Advisory contains contents of security advisories.\n\tAdvisory struct {\n\t\tText string `json:\"text\"`\n\t}\n\t// Payload returns information to the client about their existing version of a component.\n\tPayload struct {\n\t\t// Latest is set if there is a newer version to upgrade to.\n\t\tLatest *Latest `json:\"latest\"`\n\t\t// Advisory is set if security advisories exist for the current version.\n\t\tAdvisory *Advisory `json:\"advisory\"`\n\t}\n\t// VerChecker retrieves version information from the vercheck service.\n\tVerChecker struct {\n\t\tendpoint string\n\t\tstate    *cmdstate.File[State]\n\t}\n\t// State stores information about local runs of VerChecker to limit the\n\t// frequency in which clients poll the service for information.\n\tState struct {\n\t\tCheckedAt time.Time `json:\"checkedat\"`\n\t}\n)\n\nvar (\n\t// errSkip is returned when check isn't run because 24 hours haven't passed from the previous run.\n\terrSkip = errors.New(\"skip vercheck\")\n\t// Notify is the template for displaying the payload to the user.\n\tNotify *template.Template\n)\n\n// Check makes an HTTP request to endpoint to check if a new version or security advisories\n// exist for the current version. Check tries to read the latest time it was run from the\n// statePath, if found and 24 hours have not passed the check is skipped. When done, the latest\n// time is updated in statePath.\nfunc (v *VerChecker) Check(ctx context.Context, ver string) (*Payload, error) {\n\tif err := v.verifyTime(); err != nil {\n\t\treturn nil, err\n\t}\n\tendpoint, err := url.JoinPath(v.endpoint, \"atlas\", ver)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq, err := http.NewRequest(http.MethodGet, endpoint, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\taddHeaders(ctx, req)\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"status: %s\", resp.Status)\n\t}\n\tvar p Payload\n\tif err := json.NewDecoder(resp.Body).Decode(&p); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := v.state.Write(State{CheckedAt: time.Now()}); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &p, nil\n}\n\nfunc (v *VerChecker) verifyTime() error {\n\ts, err := v.state.Read()\n\tif err != nil || time.Since(s.CheckedAt) >= (time.Hour*24) {\n\t\treturn nil\n\t}\n\treturn errSkip\n}\n\n//go:embed notification.tmpl\nvar notifyTmpl string\n\nfunc init() {\n\tvar err error\n\tNotify, err = template.New(\"\").Parse(notifyTmpl)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/vercheck/vercheck_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage vercheck\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cloudapi\"\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdstate\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestVerCheck(t *testing.T) {\n\tvar path, ua string\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\toutput := `{\"latest\":{\"Version\":\"v0.7.2\",\"Summary\":\"\",\"Link\":\"https://github.com/ariga/atlas/releases/tag/v0.7.2\"},\"advisory\":null}`\n\t\tpath = r.URL.Path\n\t\tua = r.Header.Get(\"User-Agent\")\n\t\t_, _ = w.Write([]byte(output))\n\t}))\n\tdefer srv.Close()\n\n\thome := cmdstate.TestingHome(t)\n\tvc := New(srv.URL)\n\tver := \"v0.1.2\"\n\tcheck, err := vc.Check(context.Background(), ver)\n\n\trequire.EqualValues(t, \"/atlas/\"+ver, path)\n\tcloudapi.SetVersion(ver, \"\")\n\texpUA := fmt.Sprintf(\"Atlas/development (%s/%s)\", runtime.GOOS, runtime.GOARCH)\n\trequire.EqualValues(t, expUA, ua)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, &Payload{\n\t\tLatest: &Latest{\n\t\t\tVersion: \"v0.7.2\",\n\t\t\tSummary: \"\",\n\t\t\tLink:    \"https://github.com/ariga/atlas/releases/tag/v0.7.2\",\n\t\t},\n\t}, check)\n\n\tdirs, err := os.ReadDir(filepath.Join(home, \".atlas\"))\n\trequire.NoError(t, err)\n\trequire.Len(t, dirs, 1)\n}\n\nfunc TestState(t *testing.T) {\n\thrAgo, err := json.Marshal(State{CheckedAt: time.Now().Add(-time.Hour)})\n\trequire.NoError(t, err)\n\tweekAgo, err := json.Marshal(State{CheckedAt: time.Now().Add(-time.Hour * 24 * 7)})\n\trequire.NoError(t, err)\n\tfor _, tt := range []struct {\n\t\tname        string\n\t\tstate       string\n\t\texpectedRun bool\n\t}{\n\t\t{\n\t\t\tname:        \"corrupt json\",\n\t\t\tstate:       \"{\",\n\t\t\texpectedRun: true,\n\t\t},\n\t\t{\n\t\t\tname:        \"none\",\n\t\t\tstate:       \"\", // no file\n\t\t\texpectedRun: true,\n\t\t},\n\t\t{\n\t\t\tname:        \"one hr ago\",\n\t\t\tstate:       string(hrAgo),\n\t\t\texpectedRun: false,\n\t\t},\n\t\t{\n\t\t\tname:        \"one week ago\",\n\t\t\tstate:       string(weekAgo),\n\t\t\texpectedRun: true,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar ran bool\n\t\t\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tran = true\n\t\t\t\t_, _ = w.Write([]byte(`{}`))\n\t\t\t}))\n\t\t\tt.Cleanup(srv.Close)\n\t\t\thome := cmdstate.TestingHome(t)\n\t\t\tpath := filepath.Join(home, \".atlas\", StateFileName)\n\t\t\tif tt.state != \"\" {\n\t\t\t\trequire.NoError(t, os.MkdirAll(filepath.Dir(path), os.ModePerm))\n\t\t\t\trequire.NoError(t, os.WriteFile(path, []byte(tt.state), 0666))\n\t\t\t}\n\t\t\tvc := New(srv.URL)\n\t\t\t_, _ = vc.Check(context.Background(), \"v0.1.2\")\n\t\t\trequire.EqualValues(t, tt.expectedRun, ran)\n\n\t\t\tbuf, err := os.ReadFile(path)\n\t\t\trequire.NoError(t, err)\n\t\t\tif tt.expectedRun {\n\t\t\t\trequire.NotEqualValues(t, tt.state, buf)\n\t\t\t} else {\n\t\t\t\trequire.EqualValues(t, tt.state, buf)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestStatePersist(t *testing.T) {\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t_, _ = w.Write([]byte(`{}`))\n\t}))\n\tt.Cleanup(srv.Close)\n\thome := cmdstate.TestingHome(t)\n\tpath := filepath.Join(home, \".atlas\", StateFileName)\n\tvc := New(srv.URL)\n\t_, err := vc.Check(context.Background(), \"v0.1.2\")\n\trequire.NoError(t, err)\n\n\tb, err := os.ReadFile(path)\n\trequire.NoError(t, err)\n\trequire.Contains(t, string(b), `\"checkedat\":`)\n}\n\nfunc TestTemplate(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname    string\n\t\tpayload Payload\n\t\texp     string\n\t}{\n\t\t{\n\t\t\tname:    \"empty\",\n\t\t\tpayload: Payload{},\n\t\t\texp:     \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"version with summary\",\n\t\t\tpayload: Payload{\n\t\t\t\tLatest: &Latest{\n\t\t\t\t\tVersion: \"v0.7.2\",\n\t\t\t\t\tSummary: \"A great version including amazing features.\",\n\t\t\t\t\tLink:    \"https://atlasgo.io/v0.7.2\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texp: `A new version of Atlas is available (v0.7.2): https://atlasgo.io/v0.7.2\n\nA great version including amazing features.`,\n\t\t},\n\t\t{\n\t\t\tname: \"version\",\n\t\t\tpayload: Payload{\n\t\t\t\tLatest: &Latest{\n\t\t\t\t\tVersion: \"v0.7.2\",\n\t\t\t\t\tLink:    \"https://atlasgo.io/v0.7.2\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texp: `A new version of Atlas is available (v0.7.2): https://atlasgo.io/v0.7.2\n`,\n\t\t},\n\t\t{\n\t\t\tname: \"with advisory\",\n\t\t\tpayload: Payload{\n\t\t\t\tAdvisory: &Advisory{Text: \"This version contains a vulnerability, please upgrade.\"},\n\t\t\t},\n\t\t\texp: `SECURITY ADVISORY\nThis version contains a vulnerability, please upgrade.`,\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar b bytes.Buffer\n\t\t\terr := Notify.Execute(&b, tt.payload)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.EqualValues(t, tt.exp, b.String())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/version_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent && !official\n\npackage cmdapi\n\nconst (\n\tversionFmt  = \"atlas unofficial \"\n\tversionInfo = \"To download an official version, visit: https://atlasgo.io/getting-started#installation\\n\"\n)\n"
  },
  {
    "path": "cmd/atlas/internal/cmdapi/version_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent && !official\n\npackage cmdapi\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"os/exec\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestCLI_Version(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tcmd      *exec.Cmd\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"dev mode\",\n\t\t\tcmd: exec.Command(\"go\", \"run\", \"ariga.io/atlas/cmd/atlas\",\n\t\t\t\t\"version\",\n\t\t\t),\n\t\t\texpected: \"atlas unofficial version - development\\nhttps://github.com/ariga/atlas/releases/latest\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"release\",\n\t\t\tcmd: exec.Command(\"go\", \"run\",\n\t\t\t\t\"-ldflags\",\n\t\t\t\t\"-X ariga.io/atlas/cmd/atlas/internal/cmdapi.version=v1.2.3\",\n\t\t\t\t\"ariga.io/atlas/cmd/atlas\",\n\t\t\t\t\"version\",\n\t\t\t),\n\t\t\texpected: \"atlas unofficial version v1.2.3\\nhttps://github.com/ariga/atlas/releases/tag/v1.2.3\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"canary\",\n\t\t\tcmd: exec.Command(\"go\", \"run\",\n\t\t\t\t\"-ldflags\",\n\t\t\t\t\"-X ariga.io/atlas/cmd/atlas/internal/cmdapi.version=v0.3.0-6539f2704b5d-canary\",\n\t\t\t\t\"ariga.io/atlas/cmd/atlas\",\n\t\t\t\t\"version\",\n\t\t\t),\n\t\t\texpected: \"atlas unofficial version v0.3.0-6539f2704b5d-canary\\nhttps://github.com/ariga/atlas/releases/latest\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"flavor\",\n\t\t\tcmd: exec.Command(\"go\", \"run\",\n\t\t\t\t\"-ldflags\",\n\t\t\t\t\"-X ariga.io/atlas/cmd/atlas/internal/cmdapi.flavor=flavor\",\n\t\t\t\t\"ariga.io/atlas/cmd/atlas\",\n\t\t\t\t\"version\",\n\t\t\t),\n\t\t\texpected: \"atlas unofficial flavor version - development\\nhttps://github.com/ariga/atlas/releases/latest\\n\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Setenv(\"ATLAS_NO_UPDATE_NOTIFIER\", \"true\")\n\t\t\tstdout := bytes.NewBuffer(nil)\n\t\t\ttt.cmd.Stdout = stdout\n\t\t\ttt.cmd.Stderr = os.Stderr\n\t\t\trequire.NoError(t, tt.cmd.Run())\n\t\t\trequire.Equal(t, tt.expected+versionInfo, stdout.String())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdext/cmdext.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Package cmdext provides extensions to the Atlas configuration\n// file such as schema loaders, data sources and cloud connectors.\npackage cmdext\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cloudapi\"\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/aws/aws-sdk-go-v2/config\"\n\t\"github.com/aws/aws-sdk-go-v2/feature/rds/auth\"\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/hashicorp/hcl/v2/gohcl\"\n\t\"github.com/hashicorp/hcl/v2/hclsyntax\"\n\t\"github.com/zclconf/go-cty/cty\"\n\t\"github.com/zclconf/go-cty/cty/gocty\"\n\t\"gocloud.dev/runtimevar\"\n\t_ \"gocloud.dev/runtimevar/awsparamstore\"\n\t_ \"gocloud.dev/runtimevar/awssecretsmanager\"\n\t_ \"gocloud.dev/runtimevar/constantvar\"\n\t_ \"gocloud.dev/runtimevar/filevar\"\n\t_ \"gocloud.dev/runtimevar/gcpruntimeconfig\"\n\t_ \"gocloud.dev/runtimevar/gcpsecretmanager\"\n\t_ \"gocloud.dev/runtimevar/httpvar\"\n\t\"golang.org/x/oauth2/google\"\n\tsqladmin \"google.golang.org/api/sqladmin/v1beta4\"\n)\n\n// SpecOptions exposes the schema spec options like data-sources provided by this package.\nvar SpecOptions = append(\n\t[]schemahcl.Option{\n\t\tschemahcl.WithDataSource(\"sql\", Query),\n\t\tschemahcl.WithDataSource(\"external\", External),\n\t\tschemahcl.WithDataSource(\"runtimevar\", RuntimeVar),\n\t\tschemahcl.WithDataSource(\"template_dir\", TemplateDir),\n\t\tschemahcl.WithDataSource(\"remote_dir\", RemoteDir),\n\t\tschemahcl.WithDataSource(\"remote_schema\", RemoteSchema),\n\t\tschemahcl.WithDataSource(\"hcl_schema\", SchemaHCL),\n\t\tschemahcl.WithDataSource(\"external_schema\", SchemaExternal),\n\t\tschemahcl.WithDataSource(\"aws_rds_token\", AWSRDSToken),\n\t\tschemahcl.WithDataSource(\"gcp_cloudsql_token\", GCPCloudSQLToken),\n\t},\n\tspecOptions...,\n)\n\n// AtlasConfig exposes non-sensitive information returned by the \"atlas\" init-block.\n// By invoking AtlasInitBlock() a new config is returned that is set by the init block\n// defined and executed on schemahcl Eval functions.\ntype AtlasConfig struct {\n\tClient  *cloudapi.Client // Client attached to Atlas Cloud.\n\tToken   string           // User token.\n\tOrg     string           // Organization to connect to.\n\tProject string           // Optional project.\n}\n\n// RuntimeVar exposes the gocloud.dev/runtimevar as a schemahcl datasource.\n//\n//\tdata \"runtimevar\" \"pass\" {\n//\t  url = \"driver://path?query=param\"\n//\t}\n//\n//\tlocals {\n//\t  url = \"mysql://root:${data.runtimevar.pass}@:3306/\"\n//\t}\nfunc RuntimeVar(ctx context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {\n\tvar (\n\t\targs struct {\n\t\t\tURL string `hcl:\"url\"`\n\t\t}\n\t\terrorf = blockError(\"data.runtimevar\", block)\n\t)\n\tif diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {\n\t\treturn cty.NilVal, errorf(\"decoding body: %v\", diags)\n\t}\n\tu, err := sqlclient.ParseURL(args.URL)\n\tif err != nil {\n\t\treturn cty.NilVal, errorf(\"parsing url: %v\", err)\n\t}\n\tif d := u.Query().Get(\"decoder\"); d != \"\" && d != \"string\" {\n\t\treturn cty.NilVal, errorf(\"unsupported decoder: %q\", d)\n\t}\n\tq := u.Query()\n\tq.Set(\"decoder\", \"string\")\n\t// Default timeout is 10s unless specified otherwise.\n\ttimeout := 10 * time.Second\n\tif t := q.Get(\"timeout\"); t != \"\" {\n\t\tif timeout, err = time.ParseDuration(t); err != nil {\n\t\t\treturn cty.NilVal, errorf(\"parsing timeout: %v\", err)\n\t\t}\n\t\tq.Del(\"timeout\")\n\t}\n\tu.RawQuery = q.Encode()\n\tctx, cancel := context.WithTimeout(ctx, timeout)\n\tdefer cancel()\n\tvr, err := runtimevar.OpenVariable(ctx, u.String())\n\tif err != nil {\n\t\treturn cty.Value{}, errorf(\"opening variable: %v\", err)\n\t}\n\tdefer vr.Close()\n\tsnap, err := vr.Latest(ctx)\n\tif err != nil {\n\t\treturn cty.Value{}, errorf(\"getting latest snapshot: %v\", err)\n\t}\n\tsv, ok := snap.Value.(string)\n\tif !ok {\n\t\treturn cty.Value{}, errorf(\"unexpected snapshot value type: %T\", snap.Value)\n\t}\n\treturn cty.StringVal(sv), nil\n}\n\n// AWSRDSToken exposes an AWS RDS token as a schemahcl datasource.\n//\n//\tdata \"aws_rds_token\" \"token\" {\n//\t\tendpoint = \"db.hostname.io:3306\"\n//\t\tregion   = \"us-east-1\"\n//\t\tusername = \"admin\"\n//\t\tprofile  = \"prod-ext\"\n//\t}\nfunc AWSRDSToken(ctx context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {\n\tvar (\n\t\targs struct {\n\t\t\tEndpoint string `hcl:\"endpoint\"`\n\t\t\tRegion   string `hcl:\"region,optional\"`\n\t\t\tUsername string `hcl:\"username\"`\n\t\t\tProfile  string `hcl:\"profile,optional\"`\n\t\t}\n\t\terrorf = blockError(\"data.aws_rds_token\", block)\n\t)\n\tif diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {\n\t\treturn cty.NilVal, errorf(\"decoding body: %v\", diags)\n\t}\n\tcfg, err := config.LoadDefaultConfig(\n\t\tctx,\n\t\tconfig.WithSharedConfigProfile(args.Profile), // Ignored if empty.\n\t)\n\tif err != nil {\n\t\treturn cty.NilVal, errorf(\"loading aws config: %v\", err)\n\t}\n\tif args.Region == \"\" {\n\t\targs.Region = cfg.Region\n\t}\n\ttoken, err := auth.BuildAuthToken(ctx, args.Endpoint, args.Region, args.Username, cfg.Credentials)\n\tif err != nil {\n\t\treturn cty.NilVal, errorf(\"building auth token: %v\", err)\n\t}\n\treturn cty.StringVal(token), nil\n}\n\n// GCPCloudSQLToken exposes a CloudSQL token as a schemahcl datasource.\n//\n//\tdata \"gcp_cloudsql_token\" \"hello\" {}\nfunc GCPCloudSQLToken(ctx context.Context, _ *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {\n\terrorf := blockError(\"data.gcp_cloudsql_token\", block)\n\tts, err := google.DefaultTokenSource(ctx, sqladmin.SqlserviceAdminScope)\n\tif err != nil {\n\t\treturn cty.NilVal, errorf(\"finding default credentials: %v\", err)\n\t}\n\ttoken, err := ts.Token()\n\tif err != nil {\n\t\treturn cty.NilVal, errorf(\"getting token: %v\", err)\n\t}\n\treturn cty.StringVal(token.AccessToken), nil\n}\n\n// Query exposes the database/sql.Query as a schemahcl datasource.\n//\n//\tdata \"sql\" \"tenants\" {\n//\t  url = var.url\n//\t  query = <query>\n//\t  args = [<arg1>, <arg2>, ...]\n//\t}\n//\n//\tenv \"prod\" {\n//\t  for_each = toset(data.sql.tenants.values)\n//\t  url      = urlsetpath(var.url, each.value)\n//\t}\nfunc Query(ctx context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {\n\tvar (\n\t\targs struct {\n\t\t\tURL    string   `hcl:\"url\"`\n\t\t\tQuery  string   `hcl:\"query\"`\n\t\t\tRemain hcl.Body `hcl:\",remain\"`\n\t\t\tArgs   []any\n\t\t}\n\t\tvalues []cty.Value\n\t\terrorf = blockError(\"data.sql\", block)\n\t)\n\tif diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {\n\t\treturn cty.NilVal, errorf(\"decoding body: %v\", diags)\n\t}\n\tattrs, diags := args.Remain.JustAttributes()\n\tif diags.HasErrors() {\n\t\treturn cty.NilVal, errorf(\"getting attributes: %v\", diags)\n\t}\n\tif at, ok := attrs[\"args\"]; ok {\n\t\tswitch v, diags := at.Expr.Value(ectx); {\n\t\tcase diags.HasErrors():\n\t\t\treturn cty.NilVal, errorf(`evaluating \"args\": %w`, diags)\n\t\tcase !v.CanIterateElements():\n\t\t\treturn cty.NilVal, errorf(`attribute \"args\" must be a list, got: %s`, v.Type())\n\t\tdefault:\n\t\t\tfor it := v.ElementIterator(); it.Next(); {\n\t\t\t\tswitch _, v := it.Element(); v.Type() {\n\t\t\t\tcase cty.String:\n\t\t\t\t\targs.Args = append(args.Args, v.AsString())\n\t\t\t\tcase cty.Number:\n\t\t\t\t\tf, _ := v.AsBigFloat().Float64()\n\t\t\t\t\targs.Args = append(args.Args, f)\n\t\t\t\tcase cty.Bool:\n\t\t\t\t\targs.Args = append(args.Args, v.True())\n\t\t\t\tdefault:\n\t\t\t\t\treturn cty.NilVal, errorf(`attribute \"args\" must be a list of strings, numbers or booleans, got: %s`, v.Type())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdelete(attrs, \"args\")\n\t}\n\tif len(attrs) > 0 {\n\t\treturn cty.NilVal, errorf(\"unexpected attributes: %v\", attrs)\n\t}\n\tc, err := sqlclient.Open(ctx, args.URL)\n\tif err != nil {\n\t\treturn cty.NilVal, errorf(\"opening connection: %w\", err)\n\t}\n\tdefer c.Close()\n\trows, err := c.QueryContext(ctx, args.Query, args.Args...)\n\tif err != nil {\n\t\treturn cty.NilVal, errorf(\"executing query: %w\", err)\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar v any\n\t\tif err := rows.Scan(&v); err != nil {\n\t\t\treturn cty.NilVal, errorf(\"scanning row: %w\", err)\n\t\t}\n\t\tswitch v := v.(type) {\n\t\tcase bool:\n\t\t\tvalues = append(values, cty.BoolVal(v))\n\t\tcase int64:\n\t\t\tvalues = append(values, cty.NumberIntVal(v))\n\t\tcase float64:\n\t\t\tvalues = append(values, cty.NumberFloatVal(v))\n\t\tcase string:\n\t\t\tvalues = append(values, cty.StringVal(v))\n\t\tcase []byte:\n\t\t\tvalues = append(values, cty.StringVal(string(v)))\n\t\tdefault:\n\t\t\treturn cty.NilVal, errorf(\"unsupported row type: %T\", v)\n\t\t}\n\t}\n\tobj := map[string]cty.Value{\n\t\t\"count\":  cty.NumberIntVal(int64(len(values))),\n\t\t\"values\": cty.ListValEmpty(cty.NilType),\n\t\t\"value\":  cty.NilVal,\n\t}\n\tif len(values) > 0 {\n\t\tobj[\"value\"] = values[0]\n\t\tobj[\"values\"] = cty.ListVal(values)\n\t}\n\treturn cty.ObjectVal(obj), nil\n}\n\n// External allows loading data using external program execution.\n//\n//\tdata \"external\" \"env1\" {\n//\t  program = [\n//\t    \"node\",\n//\t    loadenv.js\",\n//\t  ]\n//\t}\n//\n//\tdata \"external\" \"env2\" {\n//\t  program = [\n//\t    \"bash\",\n//\t    \"-c\",\n//\t    \"env_to_json --file=${var.envfile} | jq '...' \",\n//\t  ]\n//\t}\nfunc External(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {\n\tvar (\n\t\targs struct {\n\t\t\tProgram []string `hcl:\"program\"`\n\t\t\tDir     string   `hcl:\"working_dir,optional\"`\n\t\t\tRemain  hcl.Body `hcl:\",remain\"`\n\t\t}\n\t\terrorf = blockError(\"data.external\", block)\n\t)\n\tif diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {\n\t\treturn cty.NilVal, errorf(\"decoding body: %v\", diags)\n\t}\n\tattrs, diags := args.Remain.JustAttributes()\n\tif diags.HasErrors() {\n\t\treturn cty.NilVal, errorf(\"getting attributes: %v\", diags)\n\t}\n\tif len(attrs) > 0 {\n\t\treturn cty.NilVal, errorf(\"unexpected attributes: %v\", attrs)\n\t}\n\tif len(args.Program) == 0 {\n\t\treturn cty.NilVal, errorf(\"program cannot be empty\")\n\t}\n\tcmd := exec.Command(args.Program[0], args.Program[1:]...)\n\tif args.Dir != \"\" {\n\t\tcmd.Dir = args.Dir\n\t}\n\tout, err := cmd.Output()\n\tif err != nil {\n\t\tmsg := err.Error()\n\t\tif err1 := (*exec.ExitError)(nil); errors.As(err, &err1) && len(err1.Stderr) > 0 {\n\t\t\tmsg = string(err1.Stderr)\n\t\t}\n\t\treturn cty.NilVal, errorf(\"running program %v: %v\", cmd.Path, msg)\n\t}\n\treturn cty.StringVal(string(out)), nil\n}\n\n// TemplateDir implements migrate.Dir interface for template directories.\n//\n//\tdata \"template_dir\" \"name\" {\n//\t  path = \"path/to/directory\"\n//\t  vars = {\n//\t    Env  = atlas.env\n//\t    Seed = var.seed\n//\t  }\n//\t}\n//\n//\tenv \"dev\" {\n//\t  url = \"driver://path?query=param\"\n//\t  migration {\n//\t    dir = data.template_dir.name.url\n//\t  }\n//\t}\nfunc TemplateDir(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {\n\tvar (\n\t\targs struct {\n\t\t\tPath   string   `hcl:\"path\"`\n\t\t\tRemain hcl.Body `hcl:\",remain\"`\n\t\t}\n\t\tvars   = make(map[string]any)\n\t\terrorf = blockError(\"data.template_dir\", block)\n\t)\n\tif diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {\n\t\treturn cty.NilVal, errorf(\"decoding body: %v\", diags)\n\t}\n\tattrs, diags := args.Remain.JustAttributes()\n\tif diags.HasErrors() {\n\t\treturn cty.NilVal, errorf(\"getting attributes: %v\", diags)\n\t}\n\tif vs, ok := attrs[\"vars\"]; ok {\n\t\tswitch vs, diags := vs.Expr.Value(ectx); {\n\t\tcase diags.HasErrors():\n\t\t\treturn cty.NilVal, errorf(`evaluating \"vars\": %w`, diags)\n\t\tcase !vs.CanIterateElements():\n\t\t\treturn cty.NilVal, errorf(`attribute \"vars\" must be a map, got: %s`, vs.Type())\n\t\tdefault:\n\t\t\tfor it := vs.ElementIterator(); it.Next(); {\n\t\t\t\tk, v := it.Element()\n\t\t\t\tswitch v.Type() {\n\t\t\t\tcase cty.String:\n\t\t\t\t\tvars[k.AsString()] = v.AsString()\n\t\t\t\tcase cty.Number:\n\t\t\t\t\tf, _ := v.AsBigFloat().Float64()\n\t\t\t\t\tvars[k.AsString()] = f\n\t\t\t\tcase cty.Bool:\n\t\t\t\t\tvars[k.AsString()] = v.True()\n\t\t\t\tcase cty.List(cty.String):\n\t\t\t\t\tvar s []string\n\t\t\t\t\tif err := gocty.FromCtyValue(v, &s); err != nil {\n\t\t\t\t\t\treturn cty.NilVal, errorf(\"convert strings: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t\tvars[k.AsString()] = s\n\t\t\t\tcase cty.List(cty.Number):\n\t\t\t\t\tvar s []float64\n\t\t\t\t\tif err := gocty.FromCtyValue(v, &s); err != nil {\n\t\t\t\t\t\treturn cty.NilVal, errorf(\"convert floats: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t\tvars[k.AsString()] = s\n\t\t\t\tcase cty.List(cty.Bool):\n\t\t\t\t\tvar s []bool\n\t\t\t\t\tif err := gocty.FromCtyValue(v, &s); err != nil {\n\t\t\t\t\t\treturn cty.NilVal, errorf(\"convert bools: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t\tvars[k.AsString()] = s\n\t\t\t\tdefault:\n\t\t\t\t\treturn cty.NilVal, errorf(`attribute \"vars\" must be a map of strings, numbers or booleans, got: %s`, v.Type().FriendlyName())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdelete(attrs, \"vars\")\n\t}\n\tif len(attrs) > 0 {\n\t\treturn cty.NilVal, errorf(\"unexpected attributes: %v\", attrs)\n\t}\n\tif d, err := os.Stat(args.Path); err != nil || !d.IsDir() {\n\t\treturn cty.NilVal, errorf(\"path %s is not a directory\", args.Path)\n\t}\n\tdirname := path.Join(args.Path, block.Labels[1])\n\tdir := migrate.OpenMemDir(dirname)\n\tdir.SetPath(args.Path)\n\t// Clear existing directories in case the config was called\n\t// multiple times with different variables.\n\tif files, err := dir.Files(); err != nil || len(files) > 0 {\n\t\tdir.Reset()\n\t}\n\tt := template.New(\"template_dir\").Option(\"missingkey=error\")\n\terr := filepath.Walk(args.Path, func(path string, d os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"walk path %s: %w\", path, err)\n\t\t}\n\t\tif !d.IsDir() {\n\t\t\t_, err = t.ParseFiles(path)\n\t\t}\n\t\treturn err\n\t})\n\tif err != nil {\n\t\treturn cty.NilVal, errorf(err.Error())\n\t}\n\t// Only top-level (template) files are treated as migrations.\n\tmatches, err := fs.Glob(os.DirFS(args.Path), \"*.sql\")\n\tif err != nil {\n\t\treturn cty.NilVal, errorf(\"globbing templates: %w\", err)\n\t}\n\tfor _, m := range matches {\n\t\tvar b bytes.Buffer\n\t\tif err := t.ExecuteTemplate(&b, m, vars); err != nil {\n\t\t\treturn cty.NilVal, errorf(\"executing template: %w\", err)\n\t\t}\n\t\tif err := dir.WriteFile(m, b.Bytes()); err != nil {\n\t\t\treturn cty.NilVal, errorf(\"writing file %q: %w\", m, err)\n\t\t}\n\t}\n\tsum, err := dir.Checksum()\n\tif err != nil {\n\t\treturn cty.NilVal, err\n\t}\n\tif err := migrate.WriteSumFile(dir, sum); err != nil {\n\t\treturn cty.NilVal, err\n\t}\n\t// Sync template dir to local filesystem.\n\tdir.SyncWrites(func(name string, data []byte) error {\n\t\tif name == migrate.HashFileName {\n\t\t\treturn nil\n\t\t}\n\t\tl, err := migrate.NewLocalDir(args.Path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := l.WriteFile(name, data); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tsum, err := l.Checksum()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn migrate.WriteSumFile(l, sum)\n\t})\n\tu := fmt.Sprintf(\"mem://%s\", dirname)\n\t// Allow using reading the computed dir as a state source.\n\tmemLoader.states[u] = StateLoaderFunc(func(ctx context.Context, config *StateReaderConfig) (*StateReadCloser, error) {\n\t\treturn stateReaderSQL(ctx, config, dir, nil, nil)\n\t})\n\treturn cty.ObjectVal(map[string]cty.Value{\n\t\t\"url\": cty.StringVal(u),\n\t}), nil\n}\n\n// SchemaHCL is a data source that reads an Atlas HCL schema file(s), evaluates it\n// with the given variables and exposes its resulting schema as in-memory HCL file.\nfunc SchemaHCL(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {\n\tvar (\n\t\targs struct {\n\t\t\tPaths  []string             `hcl:\"paths,optional\"`\n\t\t\tPath   string               `hcl:\"path,optional\"`\n\t\t\tVars   map[string]cty.Value `hcl:\"vars,optional\"`\n\t\t\tRemain hcl.Body             `hcl:\",remain\"`\n\t\t}\n\t\terrorf = blockError(\"data.hcl_schema\", block)\n\t)\n\tif diags := gohcl.DecodeBody(block.Body, ectx, &args); diags.HasErrors() {\n\t\treturn cty.NilVal, errorf(\"decoding body: %v\", diags)\n\t}\n\tattrs, diags := args.Remain.JustAttributes()\n\tif diags.HasErrors() {\n\t\treturn cty.NilVal, errorf(\"getting attributes: %v\", diags)\n\t}\n\tif len(attrs) > 0 {\n\t\treturn cty.NilVal, errorf(\"unexpected attributes: %v\", attrs)\n\t}\n\tpaths := args.Paths\n\tswitch {\n\tcase len(paths) != 0:\n\t\tif args.Path != \"\" {\n\t\t\treturn cty.NilVal, errorf(\"path and paths cannot be set together\")\n\t\t}\n\tcase args.Path == \"\":\n\t\treturn cty.NilVal, errorf(\"path or paths must be set\")\n\tdefault:\n\t\tpaths = []string{args.Path}\n\t}\n\tu, err := url.JoinPath(\"mem://hcl_schema\", block.Labels[1])\n\tif err != nil {\n\t\treturn cty.NilVal, errorf(\"build url: %v\", err)\n\t}\n\tmemLoader.states[u] = StateLoaderFunc(func(ctx context.Context, config *StateReaderConfig) (*StateReadCloser, error) {\n\t\tcfg := *config\n\t\tcfg.Vars = args.Vars\n\t\treturn stateReaderHCL(ctx, &cfg, paths)\n\t})\n\treturn cty.ObjectVal(map[string]cty.Value{\n\t\t\"url\": cty.StringVal(u),\n\t}), nil\n}\n\nfunc blockError(name string, b *hclsyntax.Block) func(string, ...any) error {\n\treturn func(format string, args ...any) error {\n\t\treturn fmt.Errorf(\"%s.%s: %w\", name, b.Labels[1], fmt.Errorf(format, args...))\n\t}\n}\n\ntype (\n\t// StateLoader allows loading StateReader's from external sources.\n\tStateLoader interface {\n\t\tLoadState(context.Context, *StateReaderConfig) (*StateReadCloser, error)\n\t}\n\t// The StateLoaderFunc type is an adapter to allow the use of ordinary\n\t// function as StateLoader.\n\tStateLoaderFunc func(context.Context, *StateReaderConfig) (*StateReadCloser, error)\n\n\t// MigrateDiffOptions for external migration differ.\n\tMigrateDiffOptions struct {\n\t\tName    string\n\t\tIndent  string\n\t\tTo      []string\n\t\tDir     migrate.Dir\n\t\tDev     *sqlclient.Client\n\t\tOptions []schema.DiffOption\n\t}\n\t// MigrateDiffer allows external sources to implement custom migration differs.\n\tMigrateDiffer interface {\n\t\tMigrateDiff(context.Context, *MigrateDiffOptions) error\n\t\tneedDiff([]string) bool\n\t}\n)\n\n// LoadState calls f(ctx, opts).\nfunc (f StateLoaderFunc) LoadState(ctx context.Context, opts *StateReaderConfig) (*StateReadCloser, error) {\n\treturn f(ctx, opts)\n}\n\nvar (\n\t// States is a global registry for external state loaders.\n\tStates = registry{\n\t\t\"ent\": EntLoader{},\n\t\t\"mem\": memLoader,\n\t}\n\tmemLoader       = MemLoader{states: make(map[string]StateLoader)}\n\terrNotSchemaURL = errors.New(\"missing schema in --dev-url. See: https://atlasgo.io/url\")\n)\n\ntype registry map[string]StateLoader\n\n// HasLoader returns true if the given scheme is registered.\nfunc (r registry) HasLoader(scheme string) bool {\n\t_, ok := r[scheme]\n\treturn ok\n}\n\n// Loader returns the state loader for the given scheme.\nfunc (r registry) Loader(scheme string) (StateLoader, bool) {\n\tl, ok := r[scheme]\n\treturn l, ok\n}\n\n// Differ returns the raw states differ for the given URLs, if registered.\nfunc (r registry) Differ(to []string) (MigrateDiffer, bool) {\n\tfor _, l := range r {\n\t\tif d, ok := l.(MigrateDiffer); ok && d.needDiff(to) {\n\t\t\treturn d, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// MemLoader is a StateLoader for loading data-sources\n// that were loaded into program memory.\ntype MemLoader struct {\n\tstates map[string]StateLoader\n}\n\n// LoadState loads the state loaded from data-sources into memory.\nfunc (l MemLoader) LoadState(ctx context.Context, config *StateReaderConfig) (*StateReadCloser, error) {\n\tif len(config.URLs) != 1 {\n\t\treturn nil, errors.New(`\"mem://\" requires exactly one data-source URL`)\n\t}\n\tu := config.URLs[0].String()\n\tif l.states[u] == nil {\n\t\treturn nil, fmt.Errorf(\"data-source state %q not found in memory\", u)\n\t}\n\treturn l.states[u].LoadState(ctx, config)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdext/cmdext_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage cmdext\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\n\tcmdmigrate \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/hashicorp/hcl/v2/hclsyntax\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\nvar specOptions []schemahcl.Option\n\n// RemoteSchema is a data source that for reading remote schemas.\nfunc RemoteSchema(context.Context, *hcl.EvalContext, *hclsyntax.Block) (cty.Value, error) {\n\treturn cty.Zero, UnsupportedErr(\"data.remote_schema\")\n}\n\n// RemoteDir is a data source that reads a remote migration directory.\nfunc RemoteDir(context.Context, *hcl.EvalContext, *hclsyntax.Block) (cty.Value, error) {\n\treturn cty.Zero, UnsupportedErr(\"data.remote_dir\")\n}\n\n// StateReaderAtlas returns a migrate.StateReader from an Atlas Cloud schema.\nfunc StateReaderAtlas(context.Context, *StateReaderConfig) (*StateReadCloser, error) {\n\treturn nil, UnsupportedErr(\"atlas remote state\")\n}\n\n// SchemaExternal is a data source that for reading external schemas.\nfunc SchemaExternal(context.Context, *hcl.EvalContext, *hclsyntax.Block) (cty.Value, error) {\n\treturn cty.Zero, UnsupportedErr(\"data.external_schema\")\n}\n\n// EntLoader is a StateLoader for loading ent.Schema's as StateReader's.\ntype EntLoader struct{}\n\n// LoadState returns a migrate.StateReader that reads the schema from an ent.Schema.\nfunc (l EntLoader) LoadState(context.Context, *StateReaderConfig) (*StateReadCloser, error) {\n\treturn nil, UnsupportedErr(\"ent:// scheme\")\n}\n\n// MigrateDiff returns the diff between ent.Schema and a directory.\nfunc (l EntLoader) MigrateDiff(context.Context, *MigrateDiffOptions) error {\n\treturn UnsupportedErr(\"ent:// scheme\")\n}\n\n// InitBlock returns the handler for the \"atlas\" init block.\nfunc (c *AtlasConfig) InitBlock() schemahcl.Option {\n\treturn schemahcl.WithInitBlock(\"atlas\", func(_ context.Context, ectx *hcl.EvalContext, block *hclsyntax.Block) (cty.Value, error) {\n\t\treturn cty.Zero, UnsupportedErr(\"atlas block\")\n\t})\n}\n\n// StateReaderSQL returns a migrate.StateReader from an SQL file or a directory of migrations.\nfunc StateReaderSQL(ctx context.Context, config *StateReaderConfig) (*StateReadCloser, error) {\n\tif len(config.URLs) != 1 {\n\t\treturn 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))\n\t}\n\tvar (\n\t\tdir  migrate.Dir\n\t\tpath = filepath.Join(config.URLs[0].Host, config.URLs[0].Path)\n\t)\n\tswitch fi, err := os.Stat(path); {\n\tcase err != nil:\n\t\treturn nil, err\n\t// A single schema file.\n\tcase !fi.IsDir():\n\t\tb, err := os.ReadFile(path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif bytes.Contains(b, []byte(\"-- atlas:import \")) {\n\t\t\treturn nil, UnsupportedErr(\"atlas:import directive\")\n\t\t}\n\t\tif dir, err = FilesAsDir(migrate.NewLocalFile(fi.Name(), b)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn stateSchemaSQL(ctx, config, dir)\n\t// The sum file is optional when reading the directory state.\n\tcase isSchemaDir(config.URLs[0], path):\n\t\tdirs, err := os.ReadDir(path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfiles := make([]migrate.File, 0, len(dirs))\n\t\tfor _, d := range dirs {\n\t\t\tb, err := os.ReadFile(filepath.Join(path, d.Name()))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif bytes.Contains(b, []byte(\"-- atlas:import \")) {\n\t\t\t\treturn nil, UnsupportedErr(\"atlas:import directive\")\n\t\t\t}\n\t\t\tfiles = append(files, migrate.NewLocalFile(d.Name(), b))\n\t\t}\n\t\tif dir, err = FilesAsDir(files...); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn stateSchemaSQL(ctx, config, dir)\n\t// A migration directory.\n\tdefault:\n\t\tvar opts []migrate.ReplayOption\n\t\tif dir, err = cmdmigrate.DirURL(ctx, config.URLs[0], false); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif v := config.URLs[0].Query().Get(\"version\"); v != \"\" {\n\t\t\topts = append(opts, migrate.ReplayToVersion(v))\n\t\t}\n\t\treturn stateReaderSQL(ctx, config, dir, nil, opts)\n\t}\n}\n\n// UnsupportedError wraps the standard message\n// used to present an unsupported feature error.\ntype UnsupportedError struct {\n\tErr error\n}\n\n// IsAbort implements the cmdapi.Aborter interface.\nfunc (*UnsupportedError) IsAbort() {}\n\nfunc UnsupportedErr(feature string) error {\n\tswitch runtime.GOOS {\n\tcase \"windows\":\n\t\treturn fmt.Errorf(`%s is not supported by the community version of Atlas.\n\nInstall the non-community version instead: https://atlasgo.io/docs#installation`, feature)\n\tdefault:\n\t\treturn fmt.Errorf(`%s is not supported by the community version of Atlas.\n\nInstall the non-community version instead:\n\n\tcurl -sSf https://atlasgo.sh | sh\n\nFor more installtion options, see: https://atlasgo.io/docs#installation`, feature)\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdext/cmdext_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdext_test\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdext\"\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t_ \"ariga.io/atlas/sql/sqlite\"\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\nfunc TestRuntimeVarSrc(t *testing.T) {\n\tvar (\n\t\tv struct {\n\t\t\tV string `spec:\"v\"`\n\t\t}\n\t\tstate = schemahcl.New(cmdext.SpecOptions...)\n\t)\n\terr := state.EvalBytes([]byte(`\ndata \"runtimevar\" \"pass\" {\n  url = \"constant://?val=hello+world&decoder=binary\"\n}\n\nv = data.runtimevar.pass\n`), &v, nil)\n\trequire.EqualError(t, err, `data.runtimevar.pass: unsupported decoder: \"binary\"`)\n\n\terr = state.EvalBytes([]byte(`\ndata \"runtimevar\" \"pass\" {\n  url = \"constant://?val=hello+world\"\n}\n\nv = data.runtimevar.pass\n`), &v, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, v.V, \"hello world\")\n\n\terr = state.EvalBytes([]byte(`\ndata \"runtimevar\" \"pass\" {\n  url = \"constant://?val=hello+world&decoder=string\"\n}\n\nv = data.runtimevar.pass\n`), &v, nil)\n\trequire.NoError(t, err, \"nop decoder\")\n\trequire.Equal(t, v.V, \"hello world\")\n}\n\nfunc TestRDSToken(t *testing.T) {\n\tt.Cleanup(\n\t\tbackupEnv(\"AWS_ACCESS_KEY_ID\", \"AWS_SECRET_ACCESS_KEY\"),\n\t)\n\t// Mock AWS env vars.\n\trequire.NoError(t, os.Setenv(\"AWS_ACCESS_KEY_ID\", \"EXAMPLE_KEY_ID\"))\n\trequire.NoError(t, os.Setenv(\"AWS_SECRET_ACCESS_KEY\", \"EXAMPLE_SECRET_KEY\"))\n\tvar (\n\t\tv struct {\n\t\t\tV string `spec:\"v\"`\n\t\t}\n\t\tstate = schemahcl.New(cmdext.SpecOptions...)\n\t)\n\terr := state.EvalBytes([]byte(`\ndata \"aws_rds_token\" \"token\" {\n\tendpoint = \"localhost:3306\"\n\tregion = \"us-east-1\"\n\tusername = \"root\"\n}\nv = data.aws_rds_token.token\n`), &v, nil)\n\trequire.NoError(t, err)\n\tparse, err := url.Parse(v.V)\n\trequire.NoError(t, err)\n\tq := parse.Query()\n\trequire.Equal(t, \"connect\", q.Get(\"Action\"))\n\trequire.Contains(t, q.Get(\"X-Amz-Credential\"), \"EXAMPLE_KEY_ID\")\n}\n\n// TestRDSTokenProfile verifies the profile option propagates to the AWS SDK.\nfunc TestRDSTokenProfile(t *testing.T) {\n\tdoc := `\ndata \"aws_rds_token\" \"token\" {\n\tusername = \"root\"\n\tendpoint = \"localhost:3306\"\n\tregion = \"us-east-1\"\n\tprofile = \"errorneous\"\n}\n\nv = data.aws_rds_token.token\n`\n\tvar (\n\t\tv struct {\n\t\t\tV string `spec:\"v\"`\n\t\t}\n\t\tstate = schemahcl.New(cmdext.SpecOptions...)\n\t)\n\terr := state.EvalBytes([]byte(doc), &v, nil)\n\trequire.EqualError(t, err, \"data.aws_rds_token.token: loading aws config: failed to get shared config profile, errorneous\")\n}\n\nfunc TestGCPToken(t *testing.T) {\n\tt.Cleanup(\n\t\tbackupEnv(\"GOOGLE_APPLICATION_CREDENTIALS\"),\n\t)\n\tcredsFile := filepath.Join(t.TempDir(), \"foo.json\")\n\trequire.NoError(t, os.Setenv(\"GOOGLE_APPLICATION_CREDENTIALS\", credsFile))\n\tts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.URL.String() != \"/token\" {\n\t\t\tt.Errorf(\"Unexpected exchange request URL, %v is found.\", r.URL)\n\t\t}\n\t\tjwt := r.FormValue(\"assertion\")\n\t\tpayload, err := base64.RawStdEncoding.DecodeString(strings.Split(jwt, \".\")[1])\n\t\trequire.NoError(t, err)\n\t\t// Ensure we request correct scopes\n\t\trequire.Contains(t, string(payload), `\"https://www.googleapis.com/auth/sqlservice.admin\"`)\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t// Write a fake access token to the client\n\t\tw.Write([]byte(`{\"access_token\":\"foo-bar-token\",\"scope\":\"user\",\"token_type\":\"bearer\",\"expires_in\":86400}`))\n\t}))\n\tdefer ts.Close()\n\trequire.NoError(t, os.WriteFile(credsFile, []byte(fmt.Sprintf(`{\n\t\t\"type\": \"service_account\",\n\t\t\"project_id\": \"foo-bar\",\n\t\t\"private_key_id\": \"foo-bar\",\n\t\t\"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\",\n\t\t\"client_email\": \"foo@bar.iam.gserviceaccount.com\",\n\t\t\"client_id\": \"100000000000000000000\",\n\t\t\"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n\t\t\"token_uri\": \"%s/token\",\n\t\t\"auth_provider_x509_cert_url\": \"\",\n\t\t\"client_x509_cert_url\": \"\",\n\t\t\"universe_domain\": \"googleapis.com\"\n\t}`, ts.URL)), 0644))\n\tvar (\n\t\tv struct {\n\t\t\tV string `spec:\"v\"`\n\t\t}\n\t\tstate = schemahcl.New(cmdext.SpecOptions...)\n\t)\n\terr := state.EvalBytes([]byte(`\ndata \"gcp_cloudsql_token\" \"helloworld\" {}\nv = data.gcp_cloudsql_token.helloworld\n`), &v, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"foo-bar-token\", v.V)\n}\n\nfunc TestQuerySrc(t *testing.T) {\n\tctx := context.Background()\n\tu := fmt.Sprintf(\"sqlite3://file:%s?cache=shared&_fk=1\", filepath.Join(t.TempDir(), \"test.db\"))\n\tdrv, err := sqlclient.Open(context.Background(), u)\n\trequire.NoError(t, err)\n\t_, err = drv.ExecContext(ctx, \"CREATE TABLE users (name text)\")\n\trequire.NoError(t, err)\n\t_, err = drv.ExecContext(ctx, \"INSERT INTO users (name) VALUES ('a8m')\")\n\trequire.NoError(t, err)\n\n\tvar (\n\t\tv struct {\n\t\t\tC  int      `spec:\"c\"`\n\t\t\tV  string   `spec:\"v\"`\n\t\t\tVs []string `spec:\"vs\"`\n\t\t}\n\t\tstate = schemahcl.New(cmdext.SpecOptions...)\n\t)\n\terr = state.EvalBytes([]byte(fmt.Sprintf(`\ndata \"sql\" \"user\" {\n  url   = %q\n  query = \"SELECT name FROM users\"\n}\n\nc = data.sql.user.count\nv = data.sql.user.value\nvs = data.sql.user.values\n`, u)), &v, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, 1, v.C)\n\trequire.Equal(t, \"a8m\", v.V)\n\trequire.Equal(t, []string{\"a8m\"}, v.Vs)\n}\n\nfunc TestTemplateDir(t *testing.T) {\n\tvar (\n\t\tv struct {\n\t\t\tDir string `spec:\"dir\"`\n\t\t}\n\t\tdir   = t.TempDir()\n\t\tctx   = context.Background()\n\t\tstate = schemahcl.New(cmdext.SpecOptions...)\n\t\t// language=hcl\n\t\tcfg = `\nvariable \"path\" {\n  type = string\n}\n\ndata \"template_dir\" \"tenant\" {\n  path = var.path\n  vars = {\n    Schema = \"main\"\n  }\n}\n\ndir = data.template_dir.tenant.url\n`\n\t)\n\terr := os.WriteFile(filepath.Join(dir, \"1.sql\"), []byte(\"create table {{ .Schema }}.t(c int);\"), 0644)\n\trequire.NoError(t, err)\n\terr = state.EvalBytes([]byte(cfg), &v, map[string]cty.Value{\n\t\t\"path\": cty.StringVal(dir),\n\t})\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, v.Dir)\n\td := migrate.OpenMemDir(strings.TrimPrefix(v.Dir, \"mem://\"))\n\trequire.NoError(t, migrate.Validate(d))\n\tfiles, err := d.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 1)\n\trequire.Equal(t, \"1.sql\", files[0].Name())\n\trequire.Equal(t, \"create table main.t(c int);\", string(files[0].Bytes()))\n\n\t// Directory was loaded to memory as source for readers.\n\tmem, ok := cmdext.States.Loader(\"mem\")\n\trequire.True(t, ok)\n\tu, err := url.Parse(v.Dir)\n\trequire.NoError(t, err)\n\tdev, err := sqlclient.Open(ctx, \"sqlite://test?mode=memory\")\n\trequire.NoError(t, err)\n\tsr, err := mem.LoadState(ctx, &cmdext.StateReaderConfig{\n\t\tURLs: []*url.URL{u},\n\t\tDev:  dev,\n\t})\n\trequire.NoError(t, err)\n\tr, err := sr.ReadState(ctx)\n\trequire.NoError(t, err)\n\trequire.Len(t, r.Schemas[0].Tables, 1)\n\n\t// Should not accept non-directories.\n\terr = state.EvalBytes([]byte(cfg), &v, map[string]cty.Value{\n\t\t\"path\": cty.StringVal(filepath.Join(dir, \"1.sql\")),\n\t})\n\trequire.ErrorContains(t, err, \"data.template_dir.tenant: path\", \"error prefix\")\n\trequire.ErrorContains(t, err, \"1.sql is not a directory\", \"error suffix\")\n}\n\nfunc TestSchemaHCL(t *testing.T) {\n\tvar (\n\t\tv struct {\n\t\t\tSchema string `spec:\"schema\"`\n\t\t}\n\t\tdir   = t.TempDir()\n\t\tctx   = context.Background()\n\t\tstate = schemahcl.New(cmdext.SpecOptions...)\n\t)\n\terr := os.WriteFile(filepath.Join(dir, \"schema.hcl\"), []byte(`\nvariable \"schema\" {\n  type = string\n}\n\nschema \"dynamic\" {\n  name = var.schema\n}\n\ntable \"t\" {\n  schema = schema.dynamic\n  column \"c\" {\n    type = int\n  }\n}\n`), 0644)\n\trequire.NoError(t, err)\n\terr = state.EvalBytes([]byte(`\nvariable \"path\" {\n  type = string\n}\n\ndata \"hcl_schema\" \"a8m\" {\n  path = var.path\n  vars = {\n    schema = \"a8m\"\n  }\n}\n\nschema = data.hcl_schema.a8m.url\n`), &v, map[string]cty.Value{\n\t\t\"path\": cty.StringVal(dir),\n\t})\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, v.Schema)\n\tu, err := url.Parse(v.Schema)\n\trequire.NoError(t, err)\n\tloader, ok := cmdext.States.Loader(u.Scheme)\n\trequire.True(t, ok)\n\tdrv, err := sqlclient.Open(ctx, \"sqlite://test?mode=memory&_fk=1\")\n\trequire.NoError(t, err)\n\tsr, err := loader.LoadState(ctx, &cmdext.StateReaderConfig{\n\t\tDev:  drv,\n\t\tURLs: []*url.URL{u},\n\t\t// Variables are not needed at this stage,\n\t\t// as they are defined on the data source.\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"a8m\", sr.Schema)\n\trealm, err := sr.ReadState(ctx)\n\trequire.NoError(t, err)\n\tbuf, err := drv.MarshalSpec(realm)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `table \"t\" {\n  schema = schema.a8m\n  column \"c\" {\n    null = false\n    type = int\n  }\n}\nschema \"a8m\" {\n}\n`, string(buf))\n\n\t// An empty schema case.\n\terr = os.WriteFile(filepath.Join(dir, \"schema.hcl\"), []byte(``), 0644)\n\trequire.NoError(t, err)\n\tsr, err = loader.LoadState(ctx, &cmdext.StateReaderConfig{\n\t\tDev:  drv,\n\t\tURLs: []*url.URL{u},\n\t\t// Variables are not needed at this stage,\n\t\t// as they are defined on the data source.\n\t})\n\trequire.NoError(t, err)\n\trequire.Empty(t, sr.Schema)\n\trealm, err = sr.ReadState(ctx)\n\trequire.NoError(t, err)\n\tbuf, err = drv.MarshalSpec(realm)\n\trequire.NoError(t, err)\n\trequire.Equal(t, ``, string(buf))\n}\n\nfunc TestExternal(t *testing.T) {\n\tvar (\n\t\tv struct {\n\t\t\tOutput string `spec:\"output\"`\n\t\t}\n\t\tstate = schemahcl.New(cmdext.SpecOptions...)\n\t)\n\terr := state.EvalBytes([]byte(`\ndata \"external\" \"program\" {\n  program = [\n    \"echo\",\n    \"value\",\n  ]\n}\n\noutput = trimspace(data.external.program)\n`), &v, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"value\", v.Output)\n\n\terr = state.EvalBytes([]byte(`\ndata \"external\" \"program\" {\n  program = [\n    \"echo\",\n    \"{\\\"hello\\\": \\\"world\\\"}\",\n  ]\n}\n\noutput = jsondecode(data.external.program).hello\n`), &v, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"world\", v.Output)\n\n\terr = state.EvalBytes([]byte(`\nvariable \"dot_env\" {\n  type = string\n}\n\ndata \"external\" \"dot_env\" {\n  program = [\n    \"echo\",\n\t\"${var.dot_env}\",\n  ]\n}\n\nlocals {\n  dot_env = jsondecode(data.external.dot_env)\n}\n\noutput = local.dot_env.URL\n`), &v, map[string]cty.Value{\n\t\t\"dot_env\": cty.StringVal(`{\"URL\": \"https://example.com\"}`),\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"https://example.com\", v.Output)\n}\n\n// backupEnv backs up the current value of an environment variable\n// and returns a function to restore it.\nfunc backupEnv(keys ...string) (restoreFunc func()) {\n\tbackup := make(map[string]string, len(keys))\n\tfor _, key := range keys {\n\t\toriginalValue, exists := os.LookupEnv(key)\n\t\tif exists {\n\t\t\tbackup[key] = originalValue\n\t\t}\n\t}\n\treturn func() {\n\t\tfor _, key := range keys {\n\t\t\tif originalValue, exists := backup[key]; exists {\n\t\t\t\tos.Setenv(key, originalValue)\n\t\t\t} else {\n\t\t\t\tos.Unsetenv(key)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdext/reader.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdext\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\tcmdmigrate \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/hashicorp/hcl/v2/hclsyntax\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\ntype (\n\t// StateReadCloser is a migrate.StateReader with an optional io.Closer.\n\tStateReadCloser struct {\n\t\tmigrate.StateReader\n\t\tio.Closer        // optional close function\n\t\tSchema    string // in case we work on a single schema\n\t\tHCL       bool   // true if state was read from HCL files since in that case we always compare realms\n\t}\n\t// StateReaderConfig is given to stateReader.\n\tStateReaderConfig struct {\n\t\tURLs        []*url.URL        // urls to create a migrate.StateReader from\n\t\tClient, Dev *sqlclient.Client // database connections, while dev is considered a dev database, client is not\n\t\tSchemas     []string          // schemas to work on\n\t\tExclude     []string          // exclude flag values\n\t\tInclude     []string          // include flag values\n\t\tWithPos     bool              // Indicate if schema.Pos should be loaded.\n\t\tVars        map[string]cty.Value\n\t}\n)\n\n// Close redirects calls to Close to the enclosed io.Closer.\nfunc (r *StateReadCloser) Close() error {\n\tif r.Closer != nil {\n\t\treturn r.Closer.Close()\n\t}\n\treturn nil\n}\n\n// isSchemaDir returns true if the given path is a schema directory (not a migration directory).\nfunc isSchemaDir(u *url.URL, path string) bool {\n\tif q := u.Query(); q.Has(\"version\") || q.Has(\"format\") || filepath.Base(path) == cmdmigrate.DefaultDirName {\n\t\treturn false\n\t}\n\t_, err := os.Stat(filepath.Join(path, migrate.HashFileName))\n\treturn errors.Is(err, os.ErrNotExist)\n}\n\n// errNoDevURL is returned when trying to read an SQL schema file/directory or replay a migration directory,\n// the dev-url was not set.\nvar errNoDevURL = errors.New(\"--dev-url cannot be empty. See: https://atlasgo.io/atlas-schema/sql#dev-database\")\n\n// stateSchemaSQL wraps stateReaderSQL for SQL schema files or directories to control errors when replay/read fails.\nfunc stateSchemaSQL(ctx context.Context, cfg *StateReaderConfig, dir migrate.Dir) (*StateReadCloser, error) {\n\tif cfg.Dev == nil {\n\t\treturn nil, errNoDevURL\n\t}\n\tlog := &errorRecorder{}\n\tr, err := stateReaderSQL(ctx, cfg, dir, []migrate.ExecutorOption{migrate.WithLogger(log)}, nil)\n\tif n := len(log.applied); err != nil && n > 0 && log.stmt != \"\" && log.text != \"\" {\n\t\terr = fmt.Errorf(\"read state from %q: executing statement: %q: %s\", log.applied[n-1], log.stmt, log.text)\n\t}\n\treturn r, err\n}\n\ntype errorRecorder struct {\n\tapplied    []string // applied files.\n\tstmt, text string   // error statement and text.\n}\n\n// Log implements migrate.Logger.\nfunc (r *errorRecorder) Log(e migrate.LogEntry) {\n\tswitch e := e.(type) {\n\tcase migrate.LogFile:\n\t\tr.applied = append(r.applied, e.File.Name())\n\tcase migrate.LogError:\n\t\tr.stmt = e.SQL\n\t\tr.text = e.Error.Error()\n\t}\n}\n\n// stateReaderSQL returns a migrate.StateReader from an SQL file or a directory of migrations.\nfunc stateReaderSQL(ctx context.Context, cfg *StateReaderConfig, dir migrate.Dir, optsExec []migrate.ExecutorOption, optsReplay []migrate.ReplayOption) (*StateReadCloser, error) {\n\tif cfg.Dev == nil {\n\t\treturn nil, errNoDevURL\n\t}\n\tex, err := migrate.NewExecutor(cfg.Dev.Driver, dir, migrate.NopRevisionReadWriter{}, optsExec...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsr, err := ex.Replay(ctx, func() migrate.StateReader {\n\t\tif cfg.Dev.URL.Schema != \"\" {\n\t\t\treturn migrate.SchemaConn(cfg.Dev, \"\", &schema.InspectOptions{\n\t\t\t\tExclude: cfg.Exclude,\n\t\t\t\tInclude: cfg.Include,\n\t\t\t})\n\t\t}\n\t\treturn migrate.RealmConn(cfg.Dev, &schema.InspectRealmOption{\n\t\t\tSchemas: cfg.Schemas,\n\t\t\tExclude: cfg.Exclude,\n\t\t\tInclude: cfg.Include,\n\t\t})\n\t}(), optsReplay...)\n\tif err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {\n\t\treturn nil, err\n\t}\n\treturn &StateReadCloser{\n\t\tStateReader: migrate.Realm(sr),\n\t\tSchema:      cfg.Dev.URL.Schema,\n\t}, nil\n}\n\n// StateReaderHCL returns a StateReader that reads the state from the given HCL paths urls.\nfunc StateReaderHCL(ctx context.Context, c *StateReaderConfig) (*StateReadCloser, error) {\n\tpaths := make([]string, len(c.URLs))\n\tfor i, u := range c.URLs {\n\t\tpaths[i] = filepath.Join(u.Host, u.Path)\n\t}\n\treturn stateReaderHCL(ctx, c, paths)\n}\n\n// stateReaderHCL is shared between StateReaderHCL and \"hcl_schema\" datasource.\nfunc stateReaderHCL(_ context.Context, config *StateReaderConfig, paths []string) (*StateReadCloser, error) {\n\tvar client *sqlclient.Client\n\tswitch {\n\tcase config.Dev != nil:\n\t\tclient = config.Dev\n\tcase config.Client != nil:\n\t\tclient = config.Client\n\tdefault:\n\t\treturn nil, errors.New(\"--dev-url cannot be empty\")\n\t}\n\tparser, err := parseHCLPaths(paths...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar (\n\t\teval  = client.Eval\n\t\trealm = &schema.Realm{}\n\t)\n\tif e, ok := client.Evaluator.(interface {\n\t\tEvalOptions(*hclparse.Parser, any, *schemahcl.EvalOptions) error\n\t}); ok && config.WithPos {\n\t\teval = func(pr *hclparse.Parser, v any, vars map[string]cty.Value) error {\n\t\t\treturn e.EvalOptions(pr, v, &schemahcl.EvalOptions{Variables: vars, RecordPos: true})\n\t\t}\n\t}\n\tif err := eval(parser, realm, config.Vars); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(config.Schemas) > 0 {\n\t\t// Validate all schemas in file were selected by user.\n\t\tsm := make(map[string]bool, len(config.Schemas))\n\t\tfor _, s := range config.Schemas {\n\t\t\tsm[s] = true\n\t\t}\n\t\tfor _, s := range realm.Schemas {\n\t\t\tif !sm[s.Name] {\n\t\t\t\treturn nil, fmt.Errorf(\"schema %q from paths %q is not requested (all schemas in HCL must be requested)\", s.Name, paths)\n\t\t\t}\n\t\t}\n\t}\n\t// In case the dev or client connection is bound to a specific schema, we require\n\t// the desired schema to contain only one schema. Thus, executing diff will be\n\t// done on the content of these two schema and not the whole realm.\n\tswitch {\n\tcase config.Dev != nil && config.Dev.URL.Schema != \"\" && len(realm.Schemas) > 1:\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"cannot use HCL with more than 1 schema when dev-url is limited to schema %q\",\n\t\t\tconfig.Dev.URL.Schema,\n\t\t)\n\tcase config.Client != nil && config.Client.URL.Schema != \"\" && len(realm.Schemas) > 1:\n\t\treturn nil, fmt.Errorf(\n\t\t\t\"cannot use HCL with more than 1 schema when url is limited to schema %q\",\n\t\t\tconfig.Client.URL.Schema,\n\t\t)\n\t}\n\tvar (\n\t\tnormalized  bool\n\t\tschemaScope string\n\t)\n\t// The \"Schema\" below indicates the HCL represents a single\n\t// database schema, and the work is scoped to this schema.\n\tif len(realm.Schemas) == 1 && (config.Dev != nil && config.Dev.URL.Schema != \"\" || config.Client != nil && config.Client.URL.Schema != \"\") {\n\t\tschemaScope = realm.Schemas[0].Name\n\t}\n\treturn &StateReadCloser{\n\t\tHCL:    true,\n\t\tSchema: schemaScope,\n\t\t// Defer normalization until the first call to ReadState. This is required because the same\n\t\t// dev-database is used for both migration replaying and schema normalization. As a result,\n\t\t// objects created by the migrations, which are not yet supported by Atlas, such as functions,\n\t\t// won't be cleaned and can be referenced by the HCL schema.\n\t\tStateReader: migrate.StateReaderFunc(func(ctx context.Context) (*schema.Realm, error) {\n\t\t\t// Normalize once, only on dev database connection.\n\t\t\tif nr, ok := client.Driver.(schema.Normalizer); ok && !normalized && config.Dev != nil {\n\t\t\t\tswitch {\n\t\t\t\t// Empty schema file.\n\t\t\t\tcase len(realm.Schemas) == 0:\n\t\t\t\tcase config.Dev.URL.Schema != \"\":\n\t\t\t\t\trealm.Schemas[0], err = nr.NormalizeSchema(ctx, realm.Schemas[0])\n\t\t\t\tdefault:\n\t\t\t\t\trealm, err = nr.NormalizeRealm(ctx, realm)\n\t\t\t\t}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(config.Include) > 0 {\n\t\t\t\tswitch {\n\t\t\t\tcase schemaScope != \"\" && len(realm.Schemas) == 1:\n\t\t\t\t\trealm.Schemas[0], err = schema.IncludeSchema(realm.Schemas[0], config.Include)\n\t\t\t\tdefault:\n\t\t\t\t\trealm, err = schema.IncludeRealm(realm, config.Include)\n\t\t\t\t}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(config.Exclude) > 0 {\n\t\t\t\tswitch {\n\t\t\t\tcase schemaScope != \"\" && len(realm.Schemas) == 1:\n\t\t\t\t\trealm.Schemas[0], err = schema.ExcludeSchema(realm.Schemas[0], config.Exclude)\n\t\t\t\tdefault:\n\t\t\t\t\trealm, err = schema.ExcludeRealm(realm, config.Exclude)\n\t\t\t\t}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn realm, nil\n\t\t}),\n\t}, nil\n}\n\n// FilesExt returns the file extension of the given URLs.\n// Note, all URL must have the same extension.\nfunc FilesExt(urls []*url.URL) (string, error) {\n\tvar path, ext string\n\tset := func(curr string) error {\n\t\tswitch e := filepath.Ext(curr); {\n\t\tcase e != FileTypeHCL && e != FileTypeSQL:\n\t\t\treturn fmt.Errorf(\"unknown schema file: %q\", curr)\n\t\tcase ext != \"\" && ext != e:\n\t\t\treturn fmt.Errorf(\"ambiguous schema: both SQL and HCL files found: %q, %q\", path, curr)\n\t\tdefault:\n\t\t\tpath, ext = curr, e\n\t\t\treturn nil\n\t\t}\n\t}\n\tfor _, u := range urls {\n\t\tpath := filepath.Join(u.Host, u.Path)\n\t\tswitch fi, err := os.Stat(path); {\n\t\tcase err != nil:\n\t\t\treturn \"\", err\n\t\tcase fi.IsDir():\n\t\t\tfiles, err := os.ReadDir(path)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\tfor _, f := range files {\n\t\t\t\tswitch filepath.Ext(f.Name()) {\n\t\t\t\t// Ignore unknown extensions in case we read directories.\n\t\t\t\tcase FileTypeHCL, FileTypeSQL:\n\t\t\t\t\tif err := set(f.Name()); err != nil {\n\t\t\t\t\t\treturn \"\", err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := set(fi.Name()); err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t}\n\t}\n\tswitch {\n\tcase ext != \"\":\n\tcase len(urls) == 1 && (urls[0].Host != \"\" || urls[0].Path != \"\"):\n\t\treturn \"\", fmt.Errorf(\n\t\t\t\"%q contains neither SQL nor HCL files\",\n\t\t\tfilepath.Base(filepath.Join(urls[0].Host, urls[0].Path)),\n\t\t)\n\tdefault:\n\t\treturn \"\", errors.New(\"schema contains neither SQL nor HCL files\")\n\t}\n\treturn ext, nil\n}\n\n// parseHCLPaths parses the HCL files in the given paths. If a path represents a directory,\n// its direct descendants will be considered, skipping any subdirectories. If a project file\n// is present in the input paths, an error is returned.\nfunc parseHCLPaths(paths ...string) (*hclparse.Parser, error) {\n\tp := hclparse.NewParser()\n\tfor _, path := range paths {\n\t\tswitch stat, err := os.Stat(path); {\n\t\tcase err != nil:\n\t\t\treturn nil, err\n\t\tcase stat.IsDir():\n\t\t\tdir, err := os.ReadDir(path)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tfor _, f := range dir {\n\t\t\t\t// Skip nested dirs.\n\t\t\t\tif f.IsDir() {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif err := mayParse(p, filepath.Join(path, f.Name())); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := mayParse(p, path); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\tif len(p.Files()) == 0 {\n\t\treturn nil, fmt.Errorf(\"no schema files found in: %s\", paths)\n\t}\n\treturn p, nil\n}\n\n// Schema reader types (URL schemes).\nconst (\n\tSchemaTypeFile  = \"file\"\n\tSchemaTypeAtlas = \"atlas\"\n)\n\n// File extensions supported by the file driver.\nconst (\n\tFileTypeHCL  = \".hcl\"\n\tFileTypeSQL  = \".sql\"\n\tFileTypeTest = \".test.hcl\"\n)\n\n// mayParse will parse the file in path if it is an HCL file. If the file is an Atlas\n// project file an error is returned.\nfunc mayParse(p *hclparse.Parser, path string) error {\n\tif n := filepath.Base(path); filepath.Ext(n) != FileTypeHCL && !strings.HasSuffix(path, FileTypeTest) {\n\t\treturn nil\n\t}\n\tswitch f, diag := p.ParseHCLFile(path); {\n\tcase diag.HasErrors():\n\t\treturn diag\n\tcase isProjectFile(f):\n\t\treturn fmt.Errorf(\"cannot parse project file %q as a schema file\", path)\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc isProjectFile(f *hcl.File) bool {\n\tfor _, b := range f.Body.(*hclsyntax.Body).Blocks {\n\t\tif b.Type == \"env\" {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// FilesAsDir wraps the given files as MemDir.\nfunc FilesAsDir(files ...migrate.File) (migrate.Dir, error) {\n\tdir := &migrate.MemDir{}\n\tfor _, f := range files {\n\t\tif err := dir.WriteFile(f.Name(), f.Bytes()); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\t// Create a checksum file to bypass the checksum check.\n\tsum, err := dir.Checksum()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err = migrate.WriteSumFile(dir, sum); err != nil {\n\t\treturn nil, err\n\t}\n\treturn dir, nil\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdext/reader_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdext\n\nimport (\n\t\"context\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\tcmdmigrate \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t_ \"ariga.io/atlas/sql/sqlite\"\n\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSchemaDirState(t *testing.T) {\n\tctx := context.Background()\n\tdev, err := sqlclient.Open(ctx, \"sqlite://dev?mode=memory\")\n\trequire.NoError(t, err)\n\tp1, p2 := filepath.Join(t.TempDir(), cmdmigrate.DefaultDirName), filepath.Join(t.TempDir(), \"schema\")\n\trequire.NoError(t, os.Mkdir(p1, 0755))\n\trequire.NoError(t, os.Mkdir(p2, 0755))\n\tu1, err := url.Parse(\"file://\" + p1)\n\trequire.NoError(t, err)\n\tu2, err := url.Parse(\"file://\" + p2)\n\trequire.NoError(t, err)\n\n\t// Empty migration directory.\n\tsr, err := StateReaderSQL(ctx, &StateReaderConfig{\n\t\tDev:  dev,\n\t\tURLs: []*url.URL{u1},\n\t})\n\trequire.NoError(t, err)\n\tr, err := sr.ReadState(ctx)\n\trequire.NoError(t, err)\n\trequire.Empty(t, r.Schemas[0].Tables, \"empty main schema (default SQLite schema)\")\n\n\t// Sum file is required for migrations dir (named \"migrations\").\n\td1, err := migrate.NewLocalDir(p1)\n\trequire.NoError(t, err)\n\trequire.NoError(t, d1.WriteFile(\"1.sql\", []byte(\"CREATE TABLE t1 (id INTEGER PRIMARY KEY);\")))\n\t_, err = StateReaderSQL(ctx, &StateReaderConfig{\n\t\tDev:  dev,\n\t\tURLs: []*url.URL{u1},\n\t})\n\trequire.Error(t, err, \"checksum file not found\")\n\n\t// Schema directory.\n\td2, err := migrate.NewLocalDir(p2)\n\trequire.NoError(t, err)\n\trequire.NoError(t, d2.WriteFile(\"1.sql\", []byte(\"CREATE TABLE t1 (id INTEGER PRIMARY KEY);\")))\n\tsr, err = StateReaderSQL(ctx, &StateReaderConfig{\n\t\tDev:  dev,\n\t\tURLs: []*url.URL{u2},\n\t})\n\trequire.NoError(t, err)\n\tr, err = sr.ReadState(ctx)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, r.Schemas[0].Tables, \"non-empty schema\")\n\n\t// Exclude patterns.\n\tsr, err = StateReaderSQL(ctx, &StateReaderConfig{\n\t\tDev:     dev,\n\t\tURLs:    []*url.URL{u2},\n\t\tExclude: []string{\"t1\"},\n\t})\n\trequire.NoError(t, err)\n\tr, err = sr.ReadState(ctx)\n\trequire.NoError(t, err)\n\trequire.Empty(t, r.Schemas[0].Tables, \"empty schema after excluding table\")\n\n\t// If schema contains a checksum file, it must be valid.\n\trequire.NoError(t, d2.WriteFile(migrate.HashFileName, []byte(\"invalid\")))\n\t_, err = StateReaderSQL(ctx, &StateReaderConfig{\n\t\tDev:  dev,\n\t\tURLs: []*url.URL{u2},\n\t})\n\trequire.Error(t, err, \"invalid checksum file\")\n}\n\nfunc TestStateReaderHCL(t *testing.T) {\n\tctx := context.Background()\n\tdev, err := sqlclient.Open(ctx, \"sqlite://dev?mode=memory\")\n\trequire.NoError(t, err)\n\n\tp := filepath.Join(t.TempDir(), \"schema\")\n\trequire.NoError(t, os.Mkdir(p, 0755))\n\n\t// Write an empty schema file into the directory.\n\trequire.NoError(t, os.WriteFile(p+\"/schema.hcl\", []byte(`\nschema \"default\" {}\ntable \"t1\" {\n  schema = schema.default\n  column \"id\" {\n    type = int\n  }\n  column \"name\" {\n  \ttype = text\n  }\n}`), 0644))\n\n\t// Read schema file.\n\tu, err := url.Parse(\"file://\" + p + \"/schema.hcl\")\n\tsr, err := StateReaderHCL(ctx, &StateReaderConfig{\n\t\tDev:  dev,\n\t\tURLs: []*url.URL{u},\n\t})\n\trequire.NoError(t, err)\n\tr, err := sr.ReadState(ctx)\n\trequire.NoError(t, err)\n\trequire.Equal(t, schema.NewRealm().AddSchemas(\n\t\tschema.New(\"default\").AddTables(\n\t\t\tschema.NewTable(\"t1\").AddColumns(\n\t\t\t\tschema.NewColumn(\"id\").SetType(&schema.IntegerType{\n\t\t\t\t\tT: \"int\",\n\t\t\t\t}),\n\t\t\t\tschema.NewColumn(\"name\").SetType(&schema.StringType{\n\t\t\t\t\tT: \"text\",\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t), r)\n\n\t// Read schema file with exclude patterns.\n\tsr, err = StateReaderHCL(ctx, &StateReaderConfig{\n\t\tDev:     dev,\n\t\tURLs:    []*url.URL{u},\n\t\tExclude: []string{\"*.name\"},\n\t})\n\trequire.NoError(t, err)\n\tr, err = sr.ReadState(ctx)\n\trequire.NoError(t, err)\n\t_, exists := r.Schemas[0].Tables[0].Column(\"name\")\n\trequire.False(t, exists, \"column 'name' should be excluded\")\n\n\t// Mimic multi-schema file.\n\t// Write an empty schema file into the directory.\n\trequire.NoError(t, os.WriteFile(p+\"/schema.hcl\", []byte(`\nschema \"main\" {}\nschema \"default\" {}\ntable \"t1\" {\n  schema = schema.default\n  column \"id\" {\n    type = int\n  }\n  column \"name\" {\n  \ttype = text\n  }\n}`), 0644))\n\tsr, err = StateReaderHCL(ctx, &StateReaderConfig{\n\t\tDev:  dev,\n\t\tURLs: []*url.URL{u},\n\t})\n\trequire.EqualError(t, err, `cannot use HCL with more than 1 schema when dev-url is limited to schema \"main\"`)\n\trequire.Nil(t, sr)\n\n\tsr, err = StateReaderHCL(ctx, &StateReaderConfig{\n\t\tClient: dev,\n\t\tURLs:   []*url.URL{u},\n\t})\n\trequire.EqualError(t, err, `cannot use HCL with more than 1 schema when url is limited to schema \"main\"`)\n\trequire.Nil(t, sr)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdlog/cmdlog.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdlog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"slices\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdext\"\n\tcmdmigrate \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/fatih/color\"\n)\n\nvar (\n\tColorCyan         = color.CyanString\n\tColorGray         = color.New(color.Attribute(90))\n\tColorGreen        = color.HiGreenString\n\tColorRed          = color.HiRedString\n\tColorRedBgWhiteFg = color.New(color.FgHiWhite, color.BgHiRed).SprintFunc()\n\tColorYellow       = color.YellowString\n\t// ColorTemplateFuncs are globally available functions to color strings in a report template.\n\tColorTemplateFuncs = template.FuncMap{\n\t\t\"cyan\":         ColorCyan,\n\t\t\"green\":        ColorGreen,\n\t\t\"red\":          ColorRed,\n\t\t\"redBgWhiteFg\": ColorRedBgWhiteFg,\n\t\t\"yellow\":       ColorYellow,\n\t}\n)\n\n// WithColorFuncs extends the given template.FuncMap with the color functions.\nfunc WithColorFuncs(f template.FuncMap) template.FuncMap {\n\tfor k, v := range ColorTemplateFuncs {\n\t\tf[k] = v\n\t}\n\treturn f\n}\n\ntype (\n\t// Env holds the environment information.\n\tEnv struct {\n\t\tDriver string         `json:\"Driver,omitempty\"` // Driver name.\n\t\tURL    *sqlclient.URL `json:\"URL,omitempty\"`    // URL to dev database.\n\t\tDir    string         `json:\"Dir,omitempty\"`    // Path to migration directory.\n\t}\n\n\t// Files is a slice of migrate.File. Implements json.Marshaler.\n\tFiles []migrate.File\n\n\t// File wraps migrate.File to implement json.Marshaler.\n\tFile struct{ migrate.File }\n\n\t// FileChecks represents a set of checks to run before applying a file.\n\tFileChecks struct {\n\t\tName  string     `json:\"Name,omitempty\"`  // File/group name.\n\t\tStmts []*Check   `json:\"Stmts,omitempty\"` // Checks statements executed.\n\t\tError *StmtError `json:\"Error,omitempty\"` // Assertion error.\n\t\tStart time.Time  `json:\"Start,omitempty\"` // Start assertion time.\n\t\tEnd   time.Time  `json:\"End,omitempty\"`   // End assertion time.\n\t}\n\n\t// Check represents an assertion and its status.\n\tCheck struct {\n\t\tStmt  string  `json:\"Stmt,omitempty\"`  // Assertion statement.\n\t\tError *string `json:\"Error,omitempty\"` // Assertion error, if any.\n\t}\n\n\t// StmtError groups a statement with its execution error.\n\tStmtError struct {\n\t\tStmt string `json:\"Stmt,omitempty\"` // SQL statement that failed.\n\t\tText string `json:\"Text,omitempty\"` // Error message as returned by the database.\n\t}\n)\n\n// MarshalJSON implements json.Marshaler.\nfunc (f File) MarshalJSON() ([]byte, error) {\n\ttype local struct {\n\t\tName        string `json:\"Name,omitempty\"`\n\t\tVersion     string `json:\"Version,omitempty\"`\n\t\tDescription string `json:\"Description,omitempty\"`\n\t}\n\treturn json.Marshal(local{f.Name(), f.Version(), f.Desc()})\n}\n\n// MarshalJSON implements json.Marshaler.\nfunc (f Files) MarshalJSON() ([]byte, error) {\n\tfiles := make([]File, len(f))\n\tfor i := range f {\n\t\tfiles[i] = File{f[i]}\n\t}\n\treturn json.Marshal(files)\n}\n\n// NewEnv returns an initialized Env.\nfunc NewEnv(c *sqlclient.Client, dirURL *url.URL) Env {\n\te := Env{\n\t\tDriver: c.Name,\n\t\tURL:    c.URL,\n\t}\n\tif dirURL != nil {\n\t\te.Dir = dirURL.Redacted()\n\t}\n\treturn e\n}\n\nvar (\n\t// StatusTemplateFuncs are global functions available in status report templates.\n\tStatusTemplateFuncs = WithColorFuncs(template.FuncMap{\n\t\t\"json\":       jsonEncode,\n\t\t\"json_merge\": jsonMerge,\n\t\t\"default\": func(report *MigrateStatus) (string, error) {\n\t\t\tvar buf bytes.Buffer\n\t\t\tt, err := template.New(\"report\").\n\t\t\t\tFuncs(template.FuncMap{\n\t\t\t\t\t\"add\": add,\n\t\t\t\t}).\n\t\t\t\tFuncs(ColorTemplateFuncs).\n\t\t\t\tParse(`Migration Status:\n{{- if eq .Status \"OK\" }} {{ green .Status }}{{ end }}\n{{- if eq .Status \"PENDING\" }} {{ yellow .Status }}{{ end }}\n  {{ yellow \"--\" }} Current Version: {{ cyan .Current }}\n{{- if gt .Total 0 }}{{ printf \" (%s statements applied)\" (yellow \"%d\" .Count) }}{{ end }}\n  {{ yellow \"--\" }} Next Version:    {{ if .Next }}{{ cyan .Next }}{{ if .FromCheckpoint }} (checkpoint){{ end }}{{ else }}UNKNOWN{{ end }}\n{{- if gt .Total 0 }}{{ printf \" (%s statements left)\" (yellow \"%d\" .Left) }}{{ end }}\n  {{ yellow \"--\" }} Executed Files:  {{ len .Applied }}{{ if gt .Total 0 }} (last one partially){{ end }}\n  {{ yellow \"--\" }} Pending Files:   {{ add (len .Pending) (len .OutOfOrder) }}{{ if .OutOfOrder }} ({{ if .Pending }}{{ len .OutOfOrder }} {{ end }}out of order){{ end }}\n{{- if gt .Total 0 }}\n\nLast migration attempt had errors:\n  {{ yellow \"--\" }} SQL:   {{ .SQL }}\n  {{ yellow \"--\" }} {{ red \"ERROR:\" }} {{ .Error }}\n{{- else if and .OutOfOrder .Error }}\n\n  {{ red \"ERROR:\" }} {{ .Error }}\n{{- end }}\n`)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\terr = t.Execute(&buf, report)\n\t\t\treturn buf.String(), err\n\t\t},\n\t})\n\n\t// MigrateStatusTemplate holds the default template of the 'migrate status' command.\n\tMigrateStatusTemplate = template.Must(template.New(\"report\").Funcs(StatusTemplateFuncs).Parse(\"{{ default . }}\"))\n)\n\n// MigrateStatus contains a summary of the migration status of a database.\ntype MigrateStatus struct {\n\tEnv        `json:\"Env\"`\n\tAvailable  Files               `json:\"Available,omitempty\"`  // Available migration files\n\tOutOfOrder Files               `json:\"OutOfOrder,omitempty\"` // OutOfOrder migration files\n\tPending    Files               `json:\"Pending,omitempty\"`    // Pending migration files\n\tApplied    []*migrate.Revision `json:\"Applied,omitempty\"`    // Applied migration files\n\tCurrent    string              `json:\"Current,omitempty\"`    // Current migration version\n\tNext       string              `json:\"Next,omitempty\"`       // Next migration version\n\tCount      int                 `json:\"Count,omitempty\"`      // Count of applied statements of the last revision\n\tTotal      int                 `json:\"Total,omitempty\"`      // Total statements of the last migration\n\tStatus     string              `json:\"Status,omitempty\"`     // Status of migration (OK, PENDING)\n\tError      string              `json:\"Error,omitempty\"`      // Last Error that occurred\n\tSQL        string              `json:\"SQL,omitempty\"`        // SQL that caused the last Error\n}\n\n// Left returns the amount of statements left to apply (if any).\nfunc (r *MigrateStatus) Left() int { return r.Total - r.Count }\n\n// FromCheckpoint reports if we start from a checkpoint version\n// Hence, the first file to be executed on the database is checkpoint.\nfunc (r *MigrateStatus) FromCheckpoint() bool {\n\tif len(r.Applied) > 0 || len(r.Pending) == 0 || r.Pending[0].Version() != r.Next {\n\t\treturn false\n\t}\n\tck, ok := r.Pending[0].(migrate.CheckpointFile)\n\treturn ok && ck.IsCheckpoint()\n}\n\n// StatusReporter is used to gather information about migration status.\ntype StatusReporter struct {\n\t// Client configures the connection to the database to file a MigrateStatus for.\n\tClient *sqlclient.Client\n\t// DirURL of the migration directory.\n\tDirURL *url.URL\n\t// Dir is used for scanning and validating the migration directory.\n\tDir migrate.Dir\n\t// Schema name the revision table resides in.\n\tSchema string\n}\n\n// Report creates and writes a MigrateStatus.\nfunc (r *StatusReporter) Report(ctx context.Context) (*MigrateStatus, error) {\n\trep := &MigrateStatus{Env: NewEnv(r.Client, r.DirURL)}\n\t// Check if there already is a revision table in the defined schema.\n\t// Inspect schema and check if the table does already exist.\n\tsch, err := r.Client.InspectSchema(ctx, r.Schema, &schema.InspectOptions{Tables: []string{revision.Table}})\n\tif err != nil && !schema.IsNotExistError(err) {\n\t\treturn nil, err\n\t}\n\tif schema.IsNotExistError(err) || func() bool { _, ok := sch.Table(revision.Table); return !ok }() {\n\t\t// Either schema or table does not exist.\n\t\tif rep.Available, err = migrate.FilesFromLastCheckpoint(r.Dir); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trep.Pending = rep.Available\n\t} else {\n\t\t// Both exist, fetch their data.\n\t\trrw, err := cmdmigrate.RevisionsForClient(ctx, r.Client, r.Schema)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := rrw.Migrate(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tex, err := migrate.NewExecutor(r.Client.Driver, r.Dir, rrw)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\trep.Applied, err = rrw.ReadRevisions(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif rep.Pending, err = ex.Pending(ctx); err != nil && !errors.Is(err, migrate.ErrNoPendingFiles) {\n\t\t\tif err1 := (*migrate.HistoryNonLinearError)(nil); errors.As(err, &err1) {\n\t\t\t\trep.Error = err1.Error()\n\t\t\t\trep.Status = statusPending\n\t\t\t\trep.Pending = err1.Pending\n\t\t\t\trep.OutOfOrder = err1.OutOfOrder\n\t\t\t\t// Non-linear error means at least one file was applied.\n\t\t\t\trep.Current = rep.Applied[len(rep.Applied)-1].Version\n\t\t\t\treturn rep, nil\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\t// If no files were applied, all pending files are\n\t\t// available. The first one might be a checkpoint.\n\t\tif len(rep.Applied) == 0 {\n\t\t\trep.Available = rep.Pending\n\t\t} else if rep.Available, err = r.Dir.Files(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tswitch len(rep.Pending) {\n\tcase len(rep.Available):\n\t\trep.Current = \"No migration applied yet\"\n\tdefault:\n\t\trep.Current = rep.Applied[len(rep.Applied)-1].Version\n\t}\n\tif len(rep.Pending) == 0 {\n\t\trep.Status = statusOK\n\t\trep.Next = \"Already at latest version\"\n\t} else {\n\t\trep.Status = statusPending\n\t\trep.Next = rep.Pending[0].Version()\n\t}\n\t// If the last one is partially applied (and not manually resolved).\n\tif len(rep.Applied) != 0 {\n\t\tlast := rep.Applied[len(rep.Applied)-1]\n\t\tif !last.Type.Has(migrate.RevisionTypeResolved) && last.Applied < last.Total {\n\t\t\trep.SQL = strings.ReplaceAll(last.ErrorStmt, \"\\n\", \" \")\n\t\t\trep.Error = strings.ReplaceAll(last.Error, \"\\n\", \" \")\n\t\t\trep.Count = last.Applied\n\t\t\tidx := migrate.FilesLastIndex(rep.Available, func(f migrate.File) bool {\n\t\t\t\treturn f.Version() == last.Version\n\t\t\t})\n\t\t\tif idx == -1 {\n\t\t\t\treturn nil, fmt.Errorf(\"migration file with version %q not found\", last.Version)\n\t\t\t}\n\t\t\tstmts, err := migrate.FileStmts(r.Client.Driver, rep.Available[idx])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\trep.Total = len(stmts)\n\t\t}\n\t}\n\treturn rep, nil\n}\n\nconst (\n\tstatusOK      = \"OK\"\n\tstatusPending = \"PENDING\"\n)\n\n// MigrateSetTemplate holds the default template of the 'migrate set' command.\nvar MigrateSetTemplate = template.Must(template.New(\"set\").\n\tFuncs(ColorTemplateFuncs).Parse(`\n{{- if and (not .Current) .Revisions -}}\nAll revisions deleted ({{ len .Revisions }} in total):\n{{ else if and .Current .Revisions -}}\nCurrent version is {{ cyan .Current.Version }} ({{ .Summary }}):\n{{ end }}\n{{- if .Revisions }}\n{{ range .ByVersion }}\n  {{- $text := .ColoredVersion }}{{ with .Description }}{{ $text = printf \"%s (%s)\" $text . }}{{ end }}\n  {{- printf \"  %s\\n\" $text }}\n{{- end }}\n{{ end -}}\n`))\n\ntype (\n\t// MigrateSet contains a summary of the migrate set command.\n\tMigrateSet struct {\n\t\tctx context.Context\n\t\t// Revisions that were added, removed or updated.\n\t\tRevisions []RevisionOp `json:\"Revisions,omitempty\"`\n\t\t// Current version in the revisions table.\n\t\tCurrent *migrate.Revision `json:\"Latest,omitempty\"`\n\t}\n\t// RevisionOp represents an operation done on a revision.\n\tRevisionOp struct {\n\t\t*migrate.Revision\n\t\tOp string `json:\"Op,omitempty\"`\n\t}\n)\n\n// NewMigrateSet returns a MigrateSet.\nfunc NewMigrateSet(ctx context.Context) *MigrateSet {\n\treturn &MigrateSet{ctx: ctx}\n}\n\n// ByVersion returns all revisions sorted by version.\nfunc (r *MigrateSet) ByVersion() []RevisionOp {\n\tsort.Slice(r.Revisions, func(i, j int) bool {\n\t\treturn r.Revisions[i].Version < r.Revisions[j].Version\n\t})\n\treturn r.Revisions\n}\n\n// Set records revision that was added.\nfunc (r *MigrateSet) Set(rev *migrate.Revision) {\n\tr.Revisions = append(r.Revisions, RevisionOp{Revision: rev, Op: \"set\"})\n}\n\n// Removed records revision that was added.\nfunc (r *MigrateSet) Removed(rev *migrate.Revision) {\n\tr.Revisions = append(r.Revisions, RevisionOp{Revision: rev, Op: \"remove\"})\n}\n\n// Summary returns a summary of the set operation.\nfunc (r *MigrateSet) Summary() string {\n\tvar s, d int\n\tfor i := range r.Revisions {\n\t\tswitch r.Revisions[i].Op {\n\t\tcase \"set\":\n\t\t\ts++\n\t\tdefault:\n\t\t\td++\n\t\t}\n\t}\n\tvar sum []string\n\tif s > 0 {\n\t\tsum = append(sum, fmt.Sprintf(\"%d set\", s))\n\t}\n\tif d > 0 {\n\t\tsum = append(sum, fmt.Sprintf(\"%d removed\", d))\n\t}\n\treturn strings.Join(sum, \", \")\n}\n\n// ColoredVersion returns the version of the revision with a color.\nfunc (r *RevisionOp) ColoredVersion() string {\n\tc := color.HiGreenString(\"+\")\n\tif r.Op != \"set\" {\n\t\tc = color.HiRedString(\"-\")\n\t}\n\treturn c + \" \" + r.Version\n}\n\nvar (\n\t// ApplyTemplateFuncs are global functions available in apply report templates.\n\tApplyTemplateFuncs = WithColorFuncs(template.FuncMap{\n\t\t\"add\":        add,\n\t\t\"upper\":      strings.ToUpper,\n\t\t\"json\":       jsonEncode,\n\t\t\"json_merge\": jsonMerge,\n\t\t\"indent_ln\":  indentLn,\n\t})\n\n\t// MigrateApplyTemplate holds the default template of the 'migrate apply' command.\n\tMigrateApplyTemplate = template.Must(template.\n\t\tNew(\"report\").\n\t\tFuncs(ApplyTemplateFuncs).\n\t\tParse(`{{- if not .Pending -}}\n{{- println \"No migration files to execute\" }}\n{{- else -}}\n{{- println .Header }}\n{{- range $i, $f := .Applied }}\n\t{{- println }}\n\t{{- $checkFailed := false }}\n\t{{- range $cf := $f.Checks }}\n\t\t{{- println \" \" (yellow \"--\") \"checks before migrating version\" (cyan $f.File.Version) }}\n\t\t{{- range $s := $cf.Stmts }}\n\t\t\t{{- if $s.Error }}\n\t\t\t\t{{- println \"   \" (red \"->\") (indent_ln $s.Stmt 7) }}\n\t\t\t{{- else }}\n\t\t\t\t{{- println \"   \" (cyan \"->\") (indent_ln $s.Stmt 7) }}\n\t\t\t{{- end }}\n\t\t{{- end }}\n\t\t{{- with $cf.Error }}\n\t\t\t{{- $checkFailed = true }}\n\t\t\t{{- println \"   \" (redBgWhiteFg .Text) }}\n\t\t{{- else }}\n\t\t\t{{- printf \"  %s ok (%s)\\n\\n\" (yellow \"--\") (yellow ($cf.End.Sub $cf.Start).String) }}\n\t\t{{- end }}\n\t{{- end }}\n\t{{- if $checkFailed }}\n\t\t{{- continue }} {{- /* No statements were applied. */}}\n\t{{- end }}\n\t{{- println \" \" (yellow \"--\") \"migrating version\" (cyan $f.File.Version) }}\n\t{{- range $f.Applied }}\n\t\t{{- println \"   \" (cyan \"->\") (indent_ln . 7) }}\n\t{{- end }}\n\t{{- with .Error }}\n\t\t{{- println \"   \" (redBgWhiteFg .Text) }}\n\t{{- else }}\n\t\t{{- printf \"  %s ok (%s)\\n\" (yellow \"--\") (yellow (.End.Sub .Start).String) }}\n\t{{- end }}\n{{- else }}\n\t{{- println }}\n\t{{- with .Error }}\n\t\t{{- println \"   \" (redBgWhiteFg .) }}\n\t{{- end }}\n{{- end }}\n{{- println }}\n{{- println \" \" (cyan \"-------------------------\") }}\n{{- println \" \" (.Summary \"  \") }}\n{{- end -}}\n`))\n)\n\ntype (\n\t// MigrateApply contains a summary of a migration applying attempt on a database.\n\tMigrateApply struct {\n\t\tctx context.Context\n\t\tEnv\n\t\tPending Files          `json:\"Pending,omitempty\"` // Pending migration files\n\t\tApplied []*AppliedFile `json:\"Applied,omitempty\"` // Applied files\n\t\tCurrent string         `json:\"Current,omitempty\"` // Current migration version\n\t\tTarget  string         `json:\"Target,omitempty\"`  // Target migration version\n\t\tStart   time.Time\n\t\tEnd     time.Time\n\t\t// Error is set even then, if it was not caused by a statement in a migration file,\n\t\t// but by Atlas, e.g. when committing or rolling back a transaction.\n\t\tError string `json:\"Error,omitempty\"`\n\t}\n\n\t// AppliedFile is part of an MigrateApply containing information about an applied file in a migration attempt.\n\tAppliedFile struct {\n\t\tmigrate.File\n\t\tStart   time.Time\n\t\tEnd     time.Time\n\t\tSkipped int           // Amount of skipped SQL statements in a partially applied file.\n\t\tApplied []string      // SQL statements applied with success\n\t\tChecks  []*FileChecks // Assertion checks\n\t\tError   *StmtError\n\t}\n)\n\n// NewMigrateApply returns an MigrateApply.\nfunc NewMigrateApply(ctx context.Context, client *sqlclient.Client, dirURL *url.URL) *MigrateApply {\n\treturn &MigrateApply{\n\t\tctx:   ctx,\n\t\tEnv:   NewEnv(client, dirURL),\n\t\tStart: time.Now(),\n\t}\n}\n\n// Log implements migrate.Logger.\nfunc (a *MigrateApply) Log(e migrate.LogEntry) {\n\tswitch e := e.(type) {\n\tcase migrate.LogExecution:\n\t\t// Do not set start time if it\n\t\t// was set by the constructor.\n\t\tif a.Start.IsZero() {\n\t\t\ta.Start = time.Now()\n\t\t}\n\t\ta.Current = e.From\n\t\ta.Target = e.To\n\t\ta.Pending = e.Files\n\tcase migrate.LogFile:\n\t\tif l := len(a.Applied); l > 0 {\n\t\t\tf := a.Applied[l-1]\n\t\t\tf.End = time.Now()\n\t\t}\n\t\ta.Applied = append(a.Applied, &AppliedFile{\n\t\t\tFile:    File{e.File},\n\t\t\tStart:   time.Now(),\n\t\t\tSkipped: e.Skip,\n\t\t})\n\tcase migrate.LogChecks:\n\t\tf := a.Applied[len(a.Applied)-1]\n\t\tf.Checks = append(f.Checks, &FileChecks{\n\t\t\tName:  e.Name,\n\t\t\tStart: time.Now(),\n\t\t\tStmts: make([]*Check, 0, len(e.Stmts)),\n\t\t})\n\tcase migrate.LogCheck:\n\t\tvar (\n\t\t\tf  = a.Applied[len(a.Applied)-1]\n\t\t\tcf = f.Checks[len(f.Checks)-1]\n\t\t\tck = &Check{Stmt: a.MaskedText(e.Decl)}\n\t\t)\n\t\tif e.Error != nil {\n\t\t\tm := a.MaskedErrorText(migrate.LogError{\n\t\t\t\tError: e.Error,\n\t\t\t\tStmt:  e.Decl,\n\t\t\t})\n\t\t\tck.Error = &m\n\t\t}\n\t\tcf.Stmts = append(cf.Stmts, ck)\n\tcase migrate.LogChecksDone:\n\t\tf := a.Applied[len(a.Applied)-1]\n\t\tcf := f.Checks[len(f.Checks)-1]\n\t\tcf.End = time.Now()\n\t\tif e.Error != nil {\n\t\t\tcf.Error = &StmtError{\n\t\t\t\tText: e.Error.Error(),\n\t\t\t\tStmt: cf.Stmts[len(cf.Stmts)-1].Stmt,\n\t\t\t}\n\t\t}\n\tcase migrate.LogStmt:\n\t\tf := a.Applied[len(a.Applied)-1]\n\t\tf.Applied = append(f.Applied, a.MaskedText(e.Stmt))\n\tcase migrate.LogError:\n\t\t// Error during migration.\n\t\tif l := len(a.Applied); l > 0 {\n\t\t\tf := a.Applied[len(a.Applied)-1]\n\t\t\tf.End = time.Now()\n\t\t\ta.End = f.End\n\t\t\tswitch {\n\t\t\tcase e.Stmt != nil:\n\t\t\t\tf.Error = &StmtError{\n\t\t\t\t\tStmt: a.MaskedText(e.Stmt),\n\t\t\t\t\tText: a.MaskedErrorText(e),\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tf.Error = &StmtError{Stmt: e.SQL, Text: e.Error.Error()}\n\t\t\t}\n\t\t\t// Error during pre stages, such as\n\t\t\t// scanning migration statements.\n\t\t} else {\n\t\t\ta.End = time.Now()\n\t\t\ta.Error = a.MaskedErrorText(e)\n\t\t}\n\tcase migrate.LogDone:\n\t\tn := time.Now()\n\t\tif l := len(a.Applied); l > 0 {\n\t\t\ta.Applied[l-1].End = n\n\t\t}\n\t\ta.End = n\n\t}\n}\n\n// Header returns a header of the migration log.\nfunc (a *MigrateApply) Header() string {\n\tif len(a.Pending) == 0 {\n\t\treturn \"No migration files to execute\"\n\t}\n\tvar b strings.Builder\n\tb.WriteString(\"Migrating to version \")\n\tb.WriteString(ColorCyan(a.Target))\n\tif a.Current != \"\" {\n\t\tb.WriteString(\" from \")\n\t\tb.WriteString(ColorCyan(a.Current))\n\t}\n\tb.WriteString(\" (\")\n\tb.WriteString(strconv.Itoa(len(a.Pending)))\n\tb.WriteString(\" migrations in total):\")\n\treturn b.String()\n}\n\n// Summary returns a footer of the migration log.\nfunc (a *MigrateApply) Summary(ident string) string {\n\tvar (\n\t\tpassedC, failedC int\n\t\tpassedS, failedS int\n\t\tpassedF, failedF int\n\t\tlines            = make([]string, 0, 3)\n\t)\n\tfor _, f := range a.Applied {\n\t\t// For each check file, count the\n\t\t// number of failed assertions.\n\t\tfor _, cf := range f.Checks {\n\t\t\tfor _, s := range cf.Stmts {\n\t\t\t\tif s.Error != nil {\n\t\t\t\t\tfailedC++\n\t\t\t\t} else {\n\t\t\t\t\tpassedC++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tpassedS += len(f.Applied)\n\t\tif f.Error != nil {\n\t\t\tfailedF++\n\t\t\t// Last statement failed (not an assertion).\n\t\t\tif len(f.Checks) == 0 || f.Checks[len(f.Checks)-1].Error == nil {\n\t\t\t\tpassedS--\n\t\t\t\tfailedS++\n\t\t\t}\n\t\t} else {\n\t\t\tpassedF++\n\t\t}\n\t}\n\t// Execution time.\n\tlines = append(lines, a.End.Sub(a.Start).String())\n\t// Executed files.\n\tswitch {\n\tcase passedF > 0 && failedF > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d migration%s ok, %d with errors\", passedF, plural(passedF), failedF))\n\tcase passedF > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d migration%s\", passedF, plural(passedF)))\n\tcase failedF > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d migration%s with errors\", failedF, plural(failedF)))\n\t}\n\t// Executed checks.\n\tswitch {\n\tcase passedC > 0 && failedC > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d check%s ok, %d failure%s\", passedC, plural(passedC), failedC, plural(failedC)))\n\tcase passedC > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d check%s\", passedC, plural(passedC)))\n\tcase failedC > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d check error%s\", failedC, plural(failedC)))\n\t}\n\t// Executed statements.\n\tswitch {\n\tcase passedS > 0 && failedS > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d sql statement%s ok, %d with errors\", passedS, plural(passedS), failedS))\n\tcase passedS > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d sql statement%s\", passedS, plural(passedS)))\n\tcase failedS > 0:\n\t\tlines = append(lines, fmt.Sprintf(\"%d sql statement%s with errors\", failedS, plural(failedS)))\n\t}\n\tvar b strings.Builder\n\tfor i, l := range lines {\n\t\tb.WriteString(ColorYellow(\"--\"))\n\t\tb.WriteByte(' ')\n\t\tb.WriteString(l)\n\t\tif i < len(lines)-1 {\n\t\t\tb.WriteByte('\\n')\n\t\t\tb.WriteString(ident)\n\t\t}\n\t}\n\treturn b.String()\n}\n\nfunc plural(n int) (s string) {\n\tif n > 1 {\n\t\ts += \"s\"\n\t}\n\treturn\n}\n\n// MarshalJSON implements json.Marshaler.\nfunc (a *MigrateApply) MarshalJSON() ([]byte, error) {\n\ttype Alias MigrateApply\n\tvar v struct {\n\t\t*Alias\n\t\tMessage string `json:\"Message,omitempty\"`\n\t}\n\tv.Alias = (*Alias)(a)\n\tswitch {\n\tcase a.Error != \"\":\n\tcase len(v.Applied) == 0:\n\t\tv.Message = \"No migration files to execute\"\n\tdefault:\n\t\tv.Message = fmt.Sprintf(\"Migrated to version %s from %s (%d migrations in total)\", v.Target, v.Current, len(v.Pending))\n\t}\n\treturn json.Marshal(v)\n}\n\n// MarshalJSON implements json.Marshaler.\nfunc (f *AppliedFile) MarshalJSON() ([]byte, error) {\n\ttype local struct {\n\t\tName        string     `json:\"Name,omitempty\"`\n\t\tVersion     string     `json:\"Version,omitempty\"`\n\t\tDescription string     `json:\"Description,omitempty\"`\n\t\tStart       time.Time  `json:\"Start,omitempty\"`\n\t\tEnd         time.Time  `json:\"End,omitempty\"`\n\t\tSkipped     int        `json:\"Skipped,omitempty\"`\n\t\tStmts       []string   `json:\"Applied,omitempty\"`\n\t\tError       *StmtError `json:\"Error,omitempty\"`\n\t}\n\treturn json.Marshal(local{\n\t\tName:        f.Name(),\n\t\tVersion:     f.Version(),\n\t\tDescription: f.Desc(),\n\t\tStart:       f.Start,\n\t\tEnd:         f.End,\n\t\tSkipped:     f.Skipped,\n\t\tStmts:       f.Applied,\n\t\tError:       f.Error,\n\t})\n}\n\n// SchemaPlanTemplate holds the default template of the 'schema apply --dry-run' command.\nvar SchemaPlanTemplate = template.Must(template.\n\tNew(\"plan\").\n\tFuncs(ApplyTemplateFuncs).\n\tParse(`{{- with .Changes.Pending -}}\n-- Planned Changes:\n{{ range . -}}\n{{- if .Comment -}}\n{{- printf \"-- %s%s\\n\" (slice .Comment 0 1 | upper ) (slice .Comment 1) -}}\n{{- end -}}\n{{- printf \"%s;\\n\" .Cmd -}}\n{{- end -}}\n{{- else -}}\nSchema is synced, no changes to be made\n{{ end -}}\n`))\n\n// Changes represents a list of changes that are pending or applied.\ntype Changes struct {\n\tApplied []*migrate.Change `json:\"Applied,omitempty\"` // SQL changes applied with success\n\tPending []*migrate.Change `json:\"Pending,omitempty\"` // SQL changes that were not applied\n\tError   *StmtError        `json:\"Error,omitempty\"`   // Error that occurred during applying\n}\n\n// MarshalJSON implements json.Marshaler.\nfunc (c Changes) MarshalJSON() ([]byte, error) {\n\tvar v struct {\n\t\tApplied []string   `json:\"Applied,omitempty\"`\n\t\tPending []string   `json:\"Pending,omitempty\"`\n\t\tError   *StmtError `json:\"Error,omitempty\"`\n\t}\n\tfor i := range c.Applied {\n\t\tv.Applied = append(v.Applied, c.Applied[i].Cmd)\n\t}\n\tfor i := range c.Pending {\n\t\tv.Pending = append(v.Pending, c.Pending[i].Cmd)\n\t}\n\tv.Error = c.Error\n\treturn json.Marshal(v)\n}\n\n// SchemaInspect contains a summary of the 'schema inspect' command.\ntype SchemaInspect struct {\n\tctx    context.Context\n\tclient *sqlclient.Client\n\tURL    string        `json:\"-\"`                // Target URL to inspect, my contain sensitive information.\n\tRealm  *schema.Realm `json:\"Schema,omitempty\"` // Inspected realm.\n}\n\nvar (\n\t// InspectTemplateFuncs are global functions available in inspect report templates.\n\tInspectTemplateFuncs = template.FuncMap{\n\t\t\"base64url\": base64url,\n\t\t\"sql\":       sqlInspect,\n\t\t\"json\":      jsonEncode,\n\t\t\"mermaid\":   mermaid,\n\t\t\"split\": func(...any) (string, error) {\n\t\t\treturn \"\", cmdext.UnsupportedErr(\"\\n'atlas schema inspect' with 'split' function\")\n\t\t},\n\t\t\"write\": func(...any) (string, error) {\n\t\t\treturn \"\", cmdext.UnsupportedErr(\"\\n'atlas schema inspect' with 'write' function\")\n\t\t},\n\t\t\"hcl\": func(...any) (string, error) {\n\t\t\treturn \"\", cmdext.UnsupportedErr(\"\\n'atlas schema inspect' with 'hcl' function\")\n\t\t},\n\t}\n\n\t// SchemaInspectTemplate holds the default template of the 'schema inspect' command.\n\tSchemaInspectTemplate = template.Must(template.New(\"inspect\").\n\t\tFuncs(InspectTemplateFuncs).\n\t\tParse(`{{ $.MarshalHCL }}`))\n)\n\n// NewSchemaInspect returns a SchemaInspect.\nfunc NewSchemaInspect(ctx context.Context, client *sqlclient.Client, realm *schema.Realm) *SchemaInspect {\n\treturn &SchemaInspect{ctx: ctx, client: client, Realm: realm}\n}\n\n// Client returns the client used to inspect the schema.\nfunc (s *SchemaInspect) Client() *sqlclient.Client {\n\treturn s.client\n}\n\n// MarshalHCL returns the default HCL representation of the schema.\n// Used by the template declared above.\nfunc (s *SchemaInspect) MarshalHCL() (string, error) {\n\tspec, err := s.client.MarshalSpec(s.Realm)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(spec), nil\n}\n\n// RedactedURL returns the inspected url redacted.\nfunc (s *SchemaInspect) RedactedURL() (string, error) {\n\tu, err := url.Parse(s.URL)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn u.Redacted(), nil\n}\n\n// MarshalJSON implements json.Marshaler.\nfunc (s *SchemaInspect) MarshalJSON() ([]byte, error) {\n\ttype (\n\t\tAttrs struct {\n\t\t\tComment string `json:\"comment,omitempty\"`\n\t\t\tCharset string `json:\"charset,omitempty\"`\n\t\t\tCollate string `json:\"collate,omitempty\"`\n\t\t}\n\t\tColumn struct {\n\t\t\tName string `json:\"name\"`\n\t\t\tType string `json:\"type,omitempty\"`\n\t\t\tNull bool   `json:\"null,omitempty\"`\n\t\t\tAttrs\n\t\t}\n\t\tIndexPart struct {\n\t\t\tDesc   bool   `json:\"desc,omitempty\"`\n\t\t\tColumn string `json:\"column,omitempty\"`\n\t\t\tExpr   string `json:\"expr,omitempty\"`\n\t\t}\n\t\tIndex struct {\n\t\t\tName   string      `json:\"name,omitempty\"`\n\t\t\tUnique bool        `json:\"unique,omitempty\"`\n\t\t\tParts  []IndexPart `json:\"parts,omitempty\"`\n\t\t}\n\t\tForeignKey struct {\n\t\t\tName       string   `json:\"name\"`\n\t\t\tColumns    []string `json:\"columns,omitempty\"`\n\t\t\tReferences struct {\n\t\t\t\tTable   string   `json:\"table\"`\n\t\t\t\tColumns []string `json:\"columns,omitempty\"`\n\t\t\t} `json:\"references\"`\n\t\t}\n\t\tTable struct {\n\t\t\tName        string       `json:\"name\"`\n\t\t\tColumns     []Column     `json:\"columns,omitempty\"`\n\t\t\tIndexes     []Index      `json:\"indexes,omitempty\"`\n\t\t\tPrimaryKey  *Index       `json:\"primary_key,omitempty\"`\n\t\t\tForeignKeys []ForeignKey `json:\"foreign_keys,omitempty\"`\n\t\t\tAttrs\n\t\t}\n\t\tSchema struct {\n\t\t\tName   string  `json:\"name\"`\n\t\t\tTables []Table `json:\"tables,omitempty\"`\n\t\t\tAttrs\n\t\t}\n\t)\n\tvar (\n\t\trealm struct {\n\t\t\tSchemas []Schema `json:\"schemas,omitempty\"`\n\t\t}\n\t\tsetAttrs = func(from []schema.Attr, to *Attrs) {\n\t\t\tfor i := range from {\n\t\t\t\tswitch a := from[i].(type) {\n\t\t\t\tcase *schema.Comment:\n\t\t\t\t\tto.Comment = a.Text\n\t\t\t\tcase *schema.Charset:\n\t\t\t\t\tto.Charset = a.V\n\t\t\t\tcase *schema.Collation:\n\t\t\t\t\tto.Collate = a.V\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t)\n\tfor _, s1 := range s.Realm.Schemas {\n\t\ts2 := Schema{Name: s1.Name}\n\t\tsetAttrs(s1.Attrs, &s2.Attrs)\n\t\tfor _, t1 := range s1.Tables {\n\t\t\tt2 := Table{Name: t1.Name}\n\t\t\tsetAttrs(t1.Attrs, &t2.Attrs)\n\t\t\tfor _, c1 := range t1.Columns {\n\t\t\t\tc2 := Column{\n\t\t\t\t\tName: c1.Name,\n\t\t\t\t\tType: c1.Type.Raw,\n\t\t\t\t\tNull: c1.Type.Null,\n\t\t\t\t}\n\t\t\t\tsetAttrs(c1.Attrs, &c2.Attrs)\n\t\t\t\tt2.Columns = append(t2.Columns, c2)\n\t\t\t}\n\t\t\tidxParts := func(idx *schema.Index) (parts []IndexPart) {\n\t\t\t\tfor _, p1 := range idx.Parts {\n\t\t\t\t\tp2 := IndexPart{Desc: p1.Desc}\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase p1.C != nil:\n\t\t\t\t\t\tp2.Column = p1.C.Name\n\t\t\t\t\tcase p1.X != nil:\n\t\t\t\t\t\tswitch t := p1.X.(type) {\n\t\t\t\t\t\tcase *schema.Literal:\n\t\t\t\t\t\t\tp2.Expr = t.V\n\t\t\t\t\t\tcase *schema.RawExpr:\n\t\t\t\t\t\t\tp2.Expr = t.X\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tparts = append(parts, p2)\n\t\t\t\t}\n\t\t\t\treturn parts\n\t\t\t}\n\t\t\tfor _, idx1 := range t1.Indexes {\n\t\t\t\tt2.Indexes = append(t2.Indexes, Index{\n\t\t\t\t\tName:   idx1.Name,\n\t\t\t\t\tUnique: idx1.Unique,\n\t\t\t\t\tParts:  idxParts(idx1),\n\t\t\t\t})\n\t\t\t}\n\t\t\tif t1.PrimaryKey != nil {\n\t\t\t\tt2.PrimaryKey = &Index{Parts: idxParts(t1.PrimaryKey)}\n\t\t\t}\n\t\t\tfor _, fk1 := range t1.ForeignKeys {\n\t\t\t\tfk2 := ForeignKey{Name: fk1.Symbol}\n\t\t\t\tfor _, c1 := range fk1.Columns {\n\t\t\t\t\tfk2.Columns = append(fk2.Columns, c1.Name)\n\t\t\t\t}\n\t\t\t\tfk2.References.Table = fk1.RefTable.Name\n\t\t\t\tfor _, c1 := range fk1.RefColumns {\n\t\t\t\t\tfk2.References.Columns = append(fk2.References.Columns, c1.Name)\n\t\t\t\t}\n\t\t\t\tt2.ForeignKeys = append(t2.ForeignKeys, fk2)\n\t\t\t}\n\t\t\ts2.Tables = append(s2.Tables, t2)\n\t\t}\n\t\trealm.Schemas = append(realm.Schemas, s2)\n\t}\n\treturn json.Marshal(realm)\n}\n\n// MarshalSQL returns the default SQL representation of the schema.\nfunc (s *SchemaInspect) MarshalSQL(indent ...string) (string, error) {\n\treturn sqlInspect(s, indent...)\n}\n\nfunc sqlInspect(report *SchemaInspect, indent ...string) (string, error) {\n\treturn fmtPlan(report.ctx, report.client, cmdmigrate.ChangesToRealm(report.client, report.Realm), indent)\n}\n\n// base64url assumes the input is a base64 encoded string and\n// replaces characters to make it URL safe.\nfunc base64url(s string) string {\n\treturn strings.NewReplacer(\"+\", \"-\", \"/\", \"_\", \"=\", \"\").Replace(s)\n}\n\n// SchemaDiff contains a summary of the 'schema diff' command.\ntype SchemaDiff struct {\n\tctx      context.Context\n\tclient   *sqlclient.Client\n\tFrom, To *schema.Realm\n\tChanges  []schema.Change\n}\n\nvar (\n\t// SchemaDiffFuncs are global functions available in diff report templates.\n\tSchemaDiffFuncs = template.FuncMap{\n\t\t\"sql\": sqlDiff,\n\t}\n\t// SchemaDiffTemplate holds the default template of the 'schema diff' command.\n\tSchemaDiffTemplate = template.Must(template.\n\t\tNew(\"schema_diff\").\n\t\tFuncs(SchemaDiffFuncs).\n\t\tParse(`{{- with .Changes -}}\n{{ sql $ }}\n{{- else -}}\nSchemas are synced, no changes to be made.\n{{ end -}}\n`))\n)\n\n// NewSchemaDiff returns a SchemaDiff.\nfunc NewSchemaDiff(ctx context.Context, client *sqlclient.Client, from, to *schema.Realm, changes []schema.Change) *SchemaDiff {\n\treturn &SchemaDiff{\n\t\tctx:     ctx,\n\t\tclient:  client,\n\t\tFrom:    from,\n\t\tTo:      to,\n\t\tChanges: changes,\n\t}\n}\n\n// Client returns the client used to inspect the schema.\nfunc (s *SchemaDiff) Client() *sqlclient.Client { return s.client }\n\n// MarshalSQL returns the default SQL representation of the schema.\nfunc (s *SchemaDiff) MarshalSQL(indent ...string) (string, error) {\n\treturn sqlDiff(s, indent...)\n}\n\nfunc sqlDiff(diff *SchemaDiff, indent ...string) (string, error) {\n\treturn fmtPlan(diff.ctx, diff.client, diff.Changes, indent)\n}\n\nfunc fmtPlan(ctx context.Context, client *sqlclient.Client, changes schema.Changes, indent []string, edit ...func(*migrate.Plan)) (string, error) {\n\tif len(indent) > 1 {\n\t\treturn \"\", fmt.Errorf(\"unexpected number of arguments: %d\", len(indent))\n\t}\n\tplan, err := client.PlanChanges(ctx, \"plan\", changes, func(o *migrate.PlanOptions) {\n\t\to.Mode = migrate.PlanModeDump\n\t\t// Disable object qualifier in schema-mode.\n\t\tif client.URL.Schema != \"\" {\n\t\t\to.SchemaQualifier = new(string)\n\t\t}\n\t\tif len(indent) > 0 {\n\t\t\to.Indent = indent[0]\n\t\t}\n\t})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t// Optional edit functions.\n\tfor i := range edit {\n\t\tedit[i](plan)\n\t}\n\tf, err := migrate.DefaultFormatter.FormatFile(plan)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(f.Bytes()), nil\n}\n\nfunc mermaid(i *SchemaInspect, _ ...string) (string, error) {\n\tft, ok := i.client.Driver.(interface {\n\t\tFormatType(schema.Type) (string, error)\n\t})\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"mermaid: driver does not support FormatType\")\n\t}\n\tvar (\n\t\tb       strings.Builder\n\t\tqualify = len(i.Realm.Schemas) > 1\n\t\tfuncs   = template.FuncMap{\n\t\t\t\"nospace\":    strings.NewReplacer(\" \", \"_\").Replace,\n\t\t\t\"formatType\": ft.FormatType,\n\t\t\t\"tableName\": func(t *schema.Table) string {\n\t\t\t\tif qualify {\n\t\t\t\t\treturn fmt.Sprintf(\"%[1]s_%[2]s[\\\"%[1]s.%[2]s\\\"]\", t.Schema.Name, t.Name)\n\t\t\t\t}\n\t\t\t\treturn t.Name\n\t\t\t},\n\t\t\t\"tableIdent\": func(t *schema.Table) string {\n\t\t\t\tif qualify {\n\t\t\t\t\treturn fmt.Sprintf(\"%s_%s\", t.Schema.Name, t.Name)\n\t\t\t\t}\n\t\t\t\treturn t.Name\n\t\t\t},\n\t\t\t\"pkfk\": func(t *schema.Table, c *schema.Column) string {\n\t\t\t\tvar pkfk []string\n\t\t\t\tif t.PrimaryKey != nil && slices.ContainsFunc(t.PrimaryKey.Parts, func(p *schema.IndexPart) bool { return p.C == c }) {\n\t\t\t\t\tpkfk = append(pkfk, \"PK\")\n\t\t\t\t}\n\t\t\t\tif c.ForeignKeys != nil {\n\t\t\t\t\tpkfk = append(pkfk, \"FK\")\n\t\t\t\t}\n\t\t\t\treturn strings.Join(pkfk, \",\")\n\t\t\t},\n\t\t\t\"card\": func(fk *schema.ForeignKey) string {\n\t\t\t\tvar (\n\t\t\t\t\thasU = func(t *schema.Table, cs []*schema.Column) bool {\n\t\t\t\t\t\tif t.PrimaryKey != nil && slices.EqualFunc(t.PrimaryKey.Parts, cs, func(p *schema.IndexPart, c *schema.Column) bool {\n\t\t\t\t\t\t\treturn p.C != nil && p.C.Name == c.Name\n\t\t\t\t\t\t}) {\n\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn slices.ContainsFunc(t.Indexes, func(idx *schema.Index) bool {\n\t\t\t\t\t\t\treturn idx.Unique && slices.EqualFunc(idx.Parts, cs, func(p *schema.IndexPart, c *schema.Column) bool {\n\t\t\t\t\t\t\t\treturn p.C != nil && p.C.Name == c.Name\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t\tfrom, to = \"}\", \"{\"\n\t\t\t\t)\n\t\t\t\tif hasU(fk.Table, fk.Columns) {\n\t\t\t\t\tfrom = \"|\"\n\t\t\t\t}\n\t\t\t\tif hasU(fk.RefTable, fk.RefColumns) {\n\t\t\t\t\tto = \"|\"\n\t\t\t\t}\n\t\t\t\treturn fmt.Sprintf(\"%so--o%s\", from, to)\n\t\t\t},\n\t\t}\n\t\tt = template.Must(template.New(\"mermaid\").\n\t\t\tFuncs(funcs).\n\t\t\tParse(`erDiagram\n{{- range $s := .Schemas }}\n  {{- range $t := $s.Tables }}\n    {{ tableName $t }} {\n    {{- range $c := $t.Columns }}\n      {{ formatType $c.Type.Type | nospace }} {{ nospace $c.Name }}{{ with pkfk $t $c }} {{ . }}{{ end }}\n    {{- end }}\n    }\n    {{- range $fk := $t.ForeignKeys }}\n    {{ tableIdent $t }} {{ card $fk }} {{ tableIdent $fk.RefTable }} : {{ $fk.Symbol }}\n    {{- end }}\n  {{- end }}\n{{- end }}\n`))\n\t)\n\tif err := t.Execute(&b, i.Realm); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn b.String(), nil\n}\n\nfunc jsonEncode(v any, args ...string) (string, error) {\n\tvar (\n\t\tb   []byte\n\t\terr error\n\t)\n\tswitch len(args) {\n\tcase 0:\n\t\tb, err = json.Marshal(v)\n\tcase 1:\n\t\tb, err = json.MarshalIndent(v, \"\", args[0])\n\tdefault:\n\t\tb, err = json.MarshalIndent(v, args[0], args[1])\n\t}\n\treturn string(b), err\n}\n\nfunc jsonMerge(objects ...string) (string, error) {\n\tvar r map[string]any\n\tfor i := range objects {\n\t\tif err := json.Unmarshal([]byte(objects[i]), &r); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"json_merge: %w\", err)\n\t\t}\n\t}\n\tb, err := json.Marshal(r)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"json_merge: %w\", err)\n\t}\n\treturn string(b), nil\n}\n\nfunc add(a, b int) int {\n\treturn a + b\n}\n\nfunc indentLn(input string, indent int) string {\n\tpad := strings.Repeat(\" \", indent)\n\treturn strings.ReplaceAll(input, \"\\n\", \"\\n\"+pad)\n}\n\n// noDirectives returns a slice of comments without directives.\nfunc noDirectives(comments []string) (cs []string) {\n\tfor _, c := range comments {\n\t\tif !strings.HasPrefix(c, \"-- atlas:\") {\n\t\t\tcs = append(cs, c)\n\t\t}\n\t}\n\treturn cs\n}\n\n// WarnOnce allow writing warning messages to the given writer,\n// but ensures only one message will be written in process run.\nfunc WarnOnce(w io.Writer, text string) error {\n\tif !reflect.TypeOf(w).Comparable() {\n\t\t_, err := w.Write([]byte(text))\n\t\treturn err\n\t}\n\tif _, loaded := oneWrites.LoadOrStore(w, true); !loaded {\n\t\t_, err := w.Write([]byte(text))\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// oneWrites per writer.\nvar oneWrites sync.Map\n"
  },
  {
    "path": "cmd/atlas/internal/cmdlog/cmdlog_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage cmdlog\n\nimport (\n\t\"context\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n)\n\n// SchemaApply contains a summary of a 'schema apply' execution on a database.\ntype SchemaApply struct {\n\tctx context.Context `json:\"-\"`\n\tEnv\n\tChanges Changes `json:\"Changes,omitempty\"`\n\t// General error that occurred during execution.\n\t// e.g., when committing or rolling back a transaction.\n\tError string `json:\"Error,omitempty\"`\n}\n\n// NewSchemaApply returns a SchemaApply.\nfunc NewSchemaApply(ctx context.Context, env Env, applied, pending []*migrate.Change, err *StmtError) *SchemaApply {\n\treturn &SchemaApply{\n\t\tctx: ctx,\n\t\tEnv: env,\n\t\tChanges: Changes{\n\t\t\tApplied: applied,\n\t\t\tPending: pending,\n\t\t\tError:   err,\n\t\t},\n\t}\n}\n\n// NewSchemaPlan returns a SchemaApply only with pending changes.\nfunc NewSchemaPlan(ctx context.Context, env Env, pending []*migrate.Change, err *StmtError) *SchemaApply {\n\treturn NewSchemaApply(ctx, env, nil, pending, err)\n}\n\nfunc (*MigrateApply) MaskedText(s *migrate.Stmt) string {\n\treturn s.Text // Unsupported feature.\n}\n\n// MaskedErrorText returns the masked versioned of the error, if caused by a statement.\nfunc (*MigrateApply) MaskedErrorText(e migrate.LogError) string {\n\treturn e.Error.Error() // Unsupported feature.\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdlog/cmdlog_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdlog_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"text/template\"\n\t\"time\"\n\n\tcmdmigrate \"ariga.io/atlas/cmd/atlas/internal/migrate\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdlog\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t_ \"ariga.io/atlas/sql/sqlite\"\n\n\t\"github.com/fatih/color\"\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSchemaInspect_MarshalJSON(t *testing.T) {\n\treport := &cmdlog.SchemaInspect{\n\t\tRealm: schema.NewRealm(\n\t\t\tschema.New(\"test\").\n\t\t\t\tSetComment(\"schema comment\").\n\t\t\t\tAddTables(\n\t\t\t\t\tschema.NewTable(\"users\").\n\t\t\t\t\t\tSetCharset(\"charset\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t&schema.Column{\n\t\t\t\t\t\t\t\tName: \"id\",\n\t\t\t\t\t\t\t\tType: &schema.ColumnType{Raw: \"bigint\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.Column{\n\t\t\t\t\t\t\t\tName: \"name\",\n\t\t\t\t\t\t\t\tType: &schema.ColumnType{Raw: \"varchar(255)\"},\n\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t&schema.Collation{V: \"collate\"},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\tschema.NewTable(\"posts\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t&schema.Column{\n\t\t\t\t\t\t\t\tName: \"id\",\n\t\t\t\t\t\t\t\tType: &schema.ColumnType{Raw: \"bigint\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.Column{\n\t\t\t\t\t\t\t\tName: \"text\",\n\t\t\t\t\t\t\t\tType: &schema.ColumnType{Raw: \"text\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t),\n\t\t\tschema.New(\"temp\"),\n\t\t),\n\t}\n\tb, err := report.MarshalJSON()\n\trequire.NoError(t, err)\n\tident, err := json.MarshalIndent(json.RawMessage(b), \"\", \"  \")\n\trequire.NoError(t, err)\n\trequire.Equal(t, `{\n  \"schemas\": [\n    {\n      \"name\": \"test\",\n      \"tables\": [\n        {\n          \"name\": \"users\",\n          \"columns\": [\n            {\n              \"name\": \"id\",\n              \"type\": \"bigint\"\n            },\n            {\n              \"name\": \"name\",\n              \"type\": \"varchar(255)\",\n              \"collate\": \"collate\"\n            }\n          ],\n          \"charset\": \"charset\"\n        },\n        {\n          \"name\": \"posts\",\n          \"columns\": [\n            {\n              \"name\": \"id\",\n              \"type\": \"bigint\"\n            },\n            {\n              \"name\": \"text\",\n              \"type\": \"text\"\n            }\n          ]\n        }\n      ],\n      \"comment\": \"schema comment\"\n    },\n    {\n      \"name\": \"temp\"\n    }\n  ]\n}`, string(ident))\n}\n\nfunc TestSchemaInspect_MarshalSQL(t *testing.T) {\n\tclient, err := sqlclient.Open(context.Background(), \"sqlite://ci?mode=memory&_fk=1\")\n\trequire.NoError(t, err)\n\tdefer client.Close()\n\treport := cmdlog.NewSchemaInspect(\n\t\tcontext.Background(),\n\t\tclient,\n\t\tschema.NewRealm(\n\t\t\tschema.New(\"main\").\n\t\t\t\tAddTables(\n\t\t\t\t\tschema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t\t),\n\t\t\t\t),\n\t\t),\n\t)\n\tb, err := report.MarshalSQL()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"-- Create \\\"users\\\" table\\nCREATE TABLE `users` (`id` int NOT NULL);\\n\", b)\n}\n\nfunc TestSchemaInspect_EncodeSQL(t *testing.T) {\n\tctx := context.Background()\n\tclient, err := sqlclient.Open(ctx, \"sqlite://ci?mode=memory&_fk=1\")\n\trequire.NoError(t, err)\n\tdefer client.Close()\n\terr = client.ApplyChanges(ctx, schema.Changes{\n\t\t&schema.AddTable{\n\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\tschema.NewStringColumn(\"name\", \"text\"),\n\t\t\t\t),\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\trealm, err := client.InspectRealm(ctx, nil)\n\trequire.NoError(t, err)\n\n\tvar (\n\t\tb    bytes.Buffer\n\t\ttmpl = template.Must(template.New(\"format\").Funcs(cmdlog.InspectTemplateFuncs).Parse(`{{ sql . }}`))\n\t)\n\trequire.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(ctx, client, realm)))\n\trequire.Equal(t, \"-- Create \\\"users\\\" table\\nCREATE TABLE `users` (`id` int NOT NULL, `name` text NOT NULL);\\n\", b.String())\n}\n\nfunc TestSchemaInspect_Mermaid(t *testing.T) {\n\tctx := context.Background()\n\tclient, err := sqlclient.Open(ctx, \"sqlite://ci?mode=memory&_fk=1\")\n\trequire.NoError(t, err)\n\tdefer client.Close()\n\tvar (\n\t\tb     bytes.Buffer\n\t\tusers = schema.NewTable(\"users\").\n\t\t\tAddColumns(\n\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\tschema.NewStringColumn(\"name\", \"text\"),\n\t\t\t)\n\t\ttmpl = template.Must(template.New(\"format\").Funcs(cmdlog.InspectTemplateFuncs).Parse(`{{ mermaid . }}`))\n\t)\n\trequire.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(context.Background(),\n\t\tclient,\n\t\tschema.NewRealm(schema.New(\"main\").AddTables(users))),\n\t))\n\trequire.Equal(t, `erDiagram\n    users {\n      int id\n      text name\n    }\n`, b.String())\n\n\tb.Reset()\n\tusers.SetPrimaryKey(\n\t\tschema.NewPrimaryKey(users.Columns[0]),\n\t)\n\tposts := schema.NewTable(\"posts\").\n\t\tAddColumns(\n\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\tschema.NewStringColumn(\"text\", \"text\"),\n\t\t)\n\tposts.SetPrimaryKey(\n\t\tschema.NewPrimaryKey(posts.Columns...),\n\t)\n\tposts.AddForeignKeys(\n\t\tschema.NewForeignKey(\"owner_id\").\n\t\t\tAddColumns(posts.Columns[0]).\n\t\t\tSetRefTable(users).\n\t\t\tAddRefColumns(users.Columns[0]),\n\t)\n\n\trequire.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(\n\t\tcontext.Background(),\n\t\tclient, schema.NewRealm(schema.New(\"main\").AddTables(users, posts)))),\n\t)\n\trequire.Equal(t, `erDiagram\n    users {\n      int id PK\n      text name\n    }\n    posts {\n      int id PK,FK\n      text text PK\n    }\n    posts }o--o| users : owner_id\n`, b.String())\n\n\tb.Reset()\n\trequire.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(\n\t\tcontext.Background(),\n\t\tclient,\n\t\tschema.NewRealm(\n\t\t\tschema.New(\"main\").AddTables(users),\n\t\t\tschema.New(\"temp\").AddTables(posts),\n\t\t),\n\t)))\n\trequire.Equal(t, `erDiagram\n    main_users[\"main.users\"] {\n      int id PK\n      text name\n    }\n    temp_posts[\"temp.posts\"] {\n      int id PK,FK\n      text text PK\n    }\n    temp_posts }o--o| main_users : owner_id\n`, b.String())\n\n\tb.Reset()\n\tusers.\n\t\tAddColumns(\n\t\t\tschema.NewIntColumn(\"best_friend_id\", \"int\"),\n\t\t).\n\t\tAddIndexes(\n\t\t\tschema.NewUniqueIndex(\"best_friend_id\").\n\t\t\t\tAddColumns(users.Columns[2]),\n\t\t).\n\t\tAddForeignKeys(\n\t\t\tschema.NewForeignKey(\"best_friend_id\").\n\t\t\t\tAddColumns(users.Columns[2]).\n\t\t\t\tSetRefTable(users).\n\t\t\t\tAddRefColumns(users.Columns[0]),\n\t\t)\n\trequire.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(\n\t\tcontext.Background(),\n\t\tclient,\n\t\tschema.NewRealm(schema.New(\"main\").AddTables(users)),\n\t)))\n\trequire.Equal(t, `erDiagram\n    users {\n      int id PK\n      text name\n      int best_friend_id FK\n    }\n    users |o--o| users : best_friend_id\n`, b.String())\n\n\tb.Reset()\n\tusers.\n\t\tAddColumns(\n\t\t\tschema.NewFloatColumn(\"time duration\", \"double precision\"),\n\t\t)\n\trequire.NoError(t, tmpl.Execute(&b, cmdlog.NewSchemaInspect(\n\t\tcontext.Background(),\n\t\tclient,\n\t\tschema.NewRealm(schema.New(\"main\").AddTables(users)),\n\t)))\n\trequire.Equal(t, `erDiagram\n    users {\n      int id PK\n      text name\n      int best_friend_id FK\n      double_precision time_duration\n    }\n    users |o--o| users : best_friend_id\n`, b.String())\n}\n\nfunc TestSchemaInspect_RedactedURL(t *testing.T) {\n\tcmd := cmdlog.SchemaInspect{\n\t\tURL: \"mysql://root:password@localhost:3306/test\",\n\t}\n\tu, err := cmd.RedactedURL()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"mysql://root:xxxxx@localhost:3306/test\", u)\n}\n\nfunc TestSchemaDiff_MarshalSQL(t *testing.T) {\n\tclient, err := sqlclient.Open(context.Background(), \"sqlite://ci?mode=memory&_fk=1\")\n\trequire.NoError(t, err)\n\tdefer client.Close()\n\tdiff := cmdlog.NewSchemaDiff(context.Background(), client, nil, nil, schema.Changes{\n\t\t&schema.AddTable{\n\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t),\n\t\t},\n\t})\n\tb, err := diff.MarshalSQL()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"-- Create \\\"users\\\" table\\nCREATE TABLE `users` (`id` int NOT NULL);\\n\", b)\n}\n\nfunc TestMigrateSet(t *testing.T) {\n\tvar (\n\t\tb   bytes.Buffer\n\t\tlog = &cmdlog.MigrateSet{}\n\t)\n\tcolor.NoColor = true\n\trequire.NoError(t, cmdlog.MigrateSetTemplate.Execute(&b, log))\n\trequire.Empty(t, b.String())\n\n\tlog.Current = &migrate.Revision{Version: \"1\"}\n\trequire.NoError(t, cmdlog.MigrateSetTemplate.Execute(&b, log))\n\trequire.Empty(t, b.String())\n\n\tlog.Current = &migrate.Revision{Version: \"1\"}\n\tlog.Removed(&migrate.Revision{Version: \"2\"})\n\tlog.Removed(&migrate.Revision{Version: \"3\", Description: \"desc\"})\n\trequire.NoError(t, cmdlog.MigrateSetTemplate.Execute(&b, log))\n\trequire.Equal(t, `Current version is 1 (2 removed):\n\n  - 2\n  - 3 (desc)\n\n`, b.String())\n\n\tb.Reset()\n\tlog.Set(&migrate.Revision{Version: \"1.1\", Description: \"desc\"})\n\trequire.NoError(t, cmdlog.MigrateSetTemplate.Execute(&b, log))\n\trequire.Equal(t, `Current version is 1 (1 set, 2 removed):\n\n  + 1.1 (desc)\n  - 2\n  - 3 (desc)\n\n`, b.String())\n\n\tb.Reset()\n\tlog.Current, log.Revisions = nil, nil\n\tlog.Removed(&migrate.Revision{Version: \"2\"})\n\tlog.Removed(&migrate.Revision{Version: \"3\", Description: \"desc\"})\n\trequire.NoError(t, cmdlog.MigrateSetTemplate.Execute(&b, log))\n\trequire.Equal(t, `All revisions deleted (2 in total):\n\n  - 2\n  - 3 (desc)\n\n`, b.String())\n}\n\nfunc TestMigrateApply(t *testing.T) {\n\tvar (\n\t\tb   bytes.Buffer\n\t\td   migrate.MemDir\n\t\tlog = &cmdlog.MigrateApply{Start: time.Now()}\n\t)\n\tlog.End = log.Start.Add(time.Millisecond * 10)\n\tcolor.NoColor = true\n\trequire.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))\n\trequire.Equal(t, \"No migration files to execute\\n\", b.String())\n\n\trequire.NoError(t, d.WriteFile(\"20240116000001.sql\", nil))\n\trequire.NoError(t, d.WriteFile(\"20240116000002.sql\", nil))\n\trequire.NoError(t, d.WriteFile(\"20240116000003.sql\", nil))\n\tfiles, err := d.Files()\n\trequire.NoError(t, err)\n\n\t// Single file.\n\tb.Reset()\n\tlog.Pending = files[:1]\n\tlog.Target = files[0].Version()\n\tlog.Applied = []*cmdlog.AppliedFile{\n\t\t{\n\t\t\tFile:  files[0],\n\t\t\tStart: log.Start,\n\t\t\tEnd:   log.Start.Add(time.Millisecond * 5),\n\t\t\tApplied: []string{\n\t\t\t\t\"CREATE TABLE users (id int NOT NULL);\",\n\t\t\t\t\"CREATE TABLE posts (id int NOT NULL);\",\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))\n\trequire.Equal(t, `Migrating to version 20240116000001 (1 migrations in total):\n\n  -- migrating version 20240116000001\n    -> CREATE TABLE users (id int NOT NULL);\n    -> CREATE TABLE posts (id int NOT NULL);\n  -- ok (5ms)\n\n  -------------------------\n  -- 10ms\n  -- 1 migration\n  -- 2 sql statements\n`, b.String())\n\n\t// Multiple files, with errors.\n\tb.Reset()\n\tlog.Pending = files[1:3]\n\tlog.Current = files[0].Version()\n\tlog.Target = files[2].Version()\n\tlog.Applied = []*cmdlog.AppliedFile{\n\t\t{\n\t\t\tFile:  files[1],\n\t\t\tStart: log.Start,\n\t\t\tEnd:   log.Start.Add(time.Millisecond),\n\t\t\tApplied: []string{\n\t\t\t\t\"CREATE TABLE t1 (id int NOT NULL);\",\n\t\t\t\t\"CREATE TABLE t2 (id int NOT NULL);\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tFile:  files[2],\n\t\t\tStart: log.Start,\n\t\t\tEnd:   log.Start.Add(time.Millisecond * 2),\n\t\t\tApplied: []string{\n\t\t\t\t\"CREATE TABLE t3 (id int NOT NULL);\",\n\t\t\t\t\"CREATE TABLE t4 (id int NOT NULL);\",\n\t\t\t},\n\t\t\tError: &cmdlog.StmtError{\n\t\t\t\tStmt: \"CREATE TABLE t4 (id int NOT NULL);\",\n\t\t\t\tText: \"table t4 already exists\",\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))\n\trequire.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):\n\n  -- migrating version 20240116000002\n    -> CREATE TABLE t1 (id int NOT NULL);\n    -> CREATE TABLE t2 (id int NOT NULL);\n  -- ok (1ms)\n\n  -- migrating version 20240116000003\n    -> CREATE TABLE t3 (id int NOT NULL);\n    -> CREATE TABLE t4 (id int NOT NULL);\n    table t4 already exists\n\n  -------------------------\n  -- 10ms\n  -- 1 migration ok, 1 with errors\n  -- 3 sql statements ok, 1 with errors\n`, b.String())\n\n\t// Multiple files with checks, and without errors.\n\tb.Reset()\n\tlog.Applied = []*cmdlog.AppliedFile{\n\t\t{\n\t\t\tFile:  files[1],\n\t\t\tStart: log.Start,\n\t\t\tEnd:   log.Start.Add(time.Millisecond),\n\t\t\tApplied: []string{\n\t\t\t\t\"CREATE TABLE t1 (id int NOT NULL);\",\n\t\t\t\t\"CREATE TABLE t2 (id int NOT NULL);\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tFile:  files[2],\n\t\t\tStart: log.Start,\n\t\t\tEnd:   log.Start.Add(time.Millisecond * 2),\n\t\t\tChecks: []*cmdlog.FileChecks{\n\t\t\t\t{\n\t\t\t\t\tStmts: []*cmdlog.Check{\n\t\t\t\t\t\t{Stmt: \"SELECT 1;\"},\n\t\t\t\t\t\t{Stmt: \"SELECT true;\"},\n\t\t\t\t\t},\n\t\t\t\t\tStart: log.Start,\n\t\t\t\t\tEnd:   log.Start.Add(time.Millisecond * 2),\n\t\t\t\t},\n\t\t\t},\n\t\t\tApplied: []string{\n\t\t\t\t\"CREATE TABLE t3 (id int NOT NULL);\",\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))\n\trequire.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):\n\n  -- migrating version 20240116000002\n    -> CREATE TABLE t1 (id int NOT NULL);\n    -> CREATE TABLE t2 (id int NOT NULL);\n  -- ok (1ms)\n\n  -- checks before migrating version 20240116000003\n    -> SELECT 1;\n    -> SELECT true;\n  -- ok (2ms)\n\n  -- migrating version 20240116000003\n    -> CREATE TABLE t3 (id int NOT NULL);\n  -- ok (2ms)\n\n  -------------------------\n  -- 10ms\n  -- 2 migrations\n  -- 2 checks\n  -- 3 sql statements\n`, b.String())\n\n\t// Multiple files with check errors.\n\tb.Reset()\n\tlog.Applied = []*cmdlog.AppliedFile{\n\t\t{\n\t\t\tFile:  files[1],\n\t\t\tStart: log.Start,\n\t\t\tEnd:   log.Start.Add(time.Millisecond),\n\t\t\tApplied: []string{\n\t\t\t\t\"CREATE TABLE t1 (id int NOT NULL);\",\n\t\t\t\t\"CREATE TABLE t2 (id int NOT NULL);\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tFile:  files[2],\n\t\t\tStart: log.Start,\n\t\t\tEnd:   log.Start.Add(time.Millisecond * 2),\n\t\t\tChecks: []*cmdlog.FileChecks{\n\t\t\t\t{\n\t\t\t\t\tStmts: []*cmdlog.Check{\n\t\t\t\t\t\t{Stmt: \"SELECT 1;\"},\n\t\t\t\t\t\t{Stmt: \"SELECT false;\", Error: new(string)},\n\t\t\t\t\t},\n\t\t\t\t\tStart: log.Start,\n\t\t\t\t\tEnd:   log.Start.Add(time.Millisecond * 2),\n\t\t\t\t\tError: &cmdlog.StmtError{Text: \"assertion failure\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tError: &cmdlog.StmtError{\n\t\t\t\tText: \"assertion failure\",\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))\n\trequire.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):\n\n  -- migrating version 20240116000002\n    -> CREATE TABLE t1 (id int NOT NULL);\n    -> CREATE TABLE t2 (id int NOT NULL);\n  -- ok (1ms)\n\n  -- checks before migrating version 20240116000003\n    -> SELECT 1;\n    -> SELECT false;\n    assertion failure\n\n  -------------------------\n  -- 10ms\n  -- 1 migration ok, 1 with errors\n  -- 1 check ok, 1 failure\n  -- 2 sql statements\n`, b.String())\n\n\t// Multiple files with multiple checks.\n\tb.Reset()\n\tlog.Applied = []*cmdlog.AppliedFile{\n\t\t{\n\t\t\tFile:  files[1],\n\t\t\tStart: log.Start,\n\t\t\tEnd:   log.Start.Add(time.Millisecond),\n\t\t\tApplied: []string{\n\t\t\t\t\"CREATE TABLE t1 (id int NOT NULL);\",\n\t\t\t\t\"CREATE TABLE t2 (id int NOT NULL);\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tFile:  files[2],\n\t\t\tStart: log.Start,\n\t\t\tEnd:   log.Start.Add(time.Millisecond * 2),\n\t\t\tChecks: []*cmdlog.FileChecks{\n\t\t\t\t{\n\t\t\t\t\tName: \"checks/1\",\n\t\t\t\t\tStmts: []*cmdlog.Check{\n\t\t\t\t\t\t{Stmt: \"SELECT 1;\"},\n\t\t\t\t\t\t{Stmt: \"SELECT true;\"},\n\t\t\t\t\t},\n\t\t\t\t\tStart: log.Start,\n\t\t\t\t\tEnd:   log.Start.Add(time.Millisecond * 2),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"checks/2\",\n\t\t\t\t\tStmts: []*cmdlog.Check{\n\t\t\t\t\t\t{Stmt: \"SELECT 1;\"},\n\t\t\t\t\t\t{Stmt: \"SELECT false;\", Error: new(string)},\n\t\t\t\t\t},\n\t\t\t\t\tStart: log.Start,\n\t\t\t\t\tEnd:   log.Start.Add(time.Millisecond * 2),\n\t\t\t\t\tError: &cmdlog.StmtError{Text: \"assertion failure\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tError: &cmdlog.StmtError{\n\t\t\t\tText: \"assertion failure\",\n\t\t\t},\n\t\t},\n\t}\n\trequire.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))\n\trequire.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):\n\n  -- migrating version 20240116000002\n    -> CREATE TABLE t1 (id int NOT NULL);\n    -> CREATE TABLE t2 (id int NOT NULL);\n  -- ok (1ms)\n\n  -- checks before migrating version 20240116000003\n    -> SELECT 1;\n    -> SELECT true;\n  -- ok (2ms)\n\n  -- checks before migrating version 20240116000003\n    -> SELECT 1;\n    -> SELECT false;\n    assertion failure\n\n  -------------------------\n  -- 10ms\n  -- 1 migration ok, 1 with errors\n  -- 3 checks ok, 1 failure\n  -- 2 sql statements\n`, b.String())\n\n\t// Error during plan stage.\n\tb.Reset()\n\tlog.Applied = nil\n\tlog.Error = `sql/migrate: scanning statements from \"20240116000003.sql\": 5:115: unclosed quote '\\''`\n\trequire.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))\n\trequire.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):\n\n    sql/migrate: scanning statements from \"20240116000003.sql\": 5:115: unclosed quote '\\''\n\n  -------------------------\n  -- 10ms\n`, b.String())\n}\n\nfunc TestReporter_Status(t *testing.T) {\n\tvar (\n\t\tbuf strings.Builder\n\t\tctx = context.Background()\n\t)\n\n\t// Clean.\n\tdir, err := migrate.NewLocalDir(filepath.Join(\"../migrate/testdata\", \"broken\"))\n\trequire.NoError(t, err)\n\tc, err := sqlclient.Open(ctx, \"sqlite://?mode=memory\")\n\trequire.NoError(t, err)\n\tdefer c.Close()\n\trr := &cmdlog.StatusReporter{Client: c, Dir: dir}\n\treport, err := rr.Report(ctx)\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))\n\trequire.Equal(t, `Migration Status: PENDING\n  -- Current Version: No migration applied yet\n  -- Next Version:    1\n  -- Executed Files:  0\n  -- Pending Files:   3\n`, buf.String())\n\n\t// Applied one.\n\tbuf.Reset()\n\trrw, err := cmdmigrate.NewEntRevisions(ctx, c)\n\trequire.NoError(t, err)\n\trequire.NoError(t, rrw.Migrate(ctx))\n\tex, err := migrate.NewExecutor(c.Driver, dir, rrw)\n\trequire.NoError(t, err)\n\trequire.NoError(t, ex.ExecuteN(ctx, 1))\n\trr = &cmdlog.StatusReporter{Client: c, Dir: dir}\n\treport, err = rr.Report(ctx)\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))\n\trequire.Equal(t, `Migration Status: PENDING\n  -- Current Version: 1\n  -- Next Version:    2\n  -- Executed Files:  1\n  -- Pending Files:   2\n`, buf.String())\n\n\t// Applied two.\n\tbuf.Reset()\n\trequire.NoError(t, err)\n\trequire.NoError(t, ex.ExecuteN(ctx, 1))\n\trr = &cmdlog.StatusReporter{Client: c, Dir: dir}\n\treport, err = rr.Report(ctx)\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))\n\trequire.Equal(t, `Migration Status: PENDING\n  -- Current Version: 2\n  -- Next Version:    3\n  -- Executed Files:  2\n  -- Pending Files:   1\n`, buf.String())\n\n\t// Partial three.\n\tbuf.Reset()\n\trequire.NoError(t, err)\n\trequire.Error(t, ex.ExecuteN(ctx, 1))\n\trr = &cmdlog.StatusReporter{Client: c, Dir: dir}\n\treport, err = rr.Report(ctx)\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))\n\trequire.Equal(t, `Migration Status: PENDING\n  -- Current Version: 3 (1 statements applied)\n  -- Next Version:    3 (1 statements left)\n  -- Executed Files:  3 (last one partially)\n  -- Pending Files:   1\n\nLast migration attempt had errors:\n  -- SQL:   THIS LINE ADDS A SYNTAX ERROR;\n  -- ERROR: near \"THIS\": syntax error\n`, buf.String())\n\n\t// Fixed three - okay.\n\tbuf.Reset()\n\tdir2, err := migrate.NewLocalDir(filepath.Join(\"../migrate/testdata\", \"fixed\"))\n\trequire.NoError(t, err)\n\t*dir = *dir2\n\trequire.NoError(t, err)\n\trequire.NoError(t, ex.ExecuteN(ctx, 1))\n\trr = &cmdlog.StatusReporter{Client: c, Dir: dir}\n\treport, err = rr.Report(ctx)\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))\n\trequire.Equal(t, `Migration Status: OK\n  -- Current Version: 3\n  -- Next Version:    Already at latest version\n  -- Executed Files:  3\n  -- Pending Files:   0\n`, buf.String())\n}\n\nfunc TestReporter_OutOfOrder(t *testing.T) {\n\tvar (\n\t\tbuf strings.Builder\n\t\tctx = context.Background()\n\t)\n\tdir, err := migrate.NewLocalDir(t.TempDir())\n\trequire.NoError(t, err)\n\trequire.NoError(t, dir.WriteFile(\"1.sql\", []byte(\"create table t1(c int);\")))\n\trequire.NoError(t, dir.WriteFile(\"2.sql\", []byte(\"create table t2(c int);\")))\n\tsum, err := dir.Checksum()\n\trequire.NoError(t, err)\n\trequire.NoError(t, migrate.WriteSumFile(dir, sum))\n\tc, err := sqlclient.Open(ctx, \"sqlite://?mode=memory\")\n\trequire.NoError(t, err)\n\tdefer c.Close()\n\trr := &cmdlog.StatusReporter{Client: c, Dir: dir}\n\n\trrw, err := cmdmigrate.NewEntRevisions(ctx, c)\n\trequire.NoError(t, err)\n\trequire.NoError(t, rrw.Migrate(ctx))\n\treport, err := rr.Report(ctx)\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))\n\trequire.Equal(t, `Migration Status: PENDING\n  -- Current Version: No migration applied yet\n  -- Next Version:    1\n  -- Executed Files:  0\n  -- Pending Files:   2\n`, buf.String())\n\n\tex, err := migrate.NewExecutor(c.Driver, dir, rrw)\n\trequire.NoError(t, err)\n\trequire.NoError(t, ex.ExecuteN(ctx, 2))\n\n\t// One file was added out of order.\n\tbuf.Reset()\n\trequire.NoError(t, dir.WriteFile(\"1.5.sql\", []byte(\"create table t1_5(c int);\")))\n\tsum, err = dir.Checksum()\n\trequire.NoError(t, err)\n\trequire.NoError(t, migrate.WriteSumFile(dir, sum))\n\treport, err = rr.Report(ctx)\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))\n\trequire.Equal(t, `Migration Status: PENDING\n  -- Current Version: 2\n  -- Next Version:    UNKNOWN\n  -- Executed Files:  2\n  -- Pending Files:   1 (out of order)\n\n  ERROR: migration file 1.5.sql was added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error\n`, buf.String())\n\n\t// Multiple files were added our of order.\n\tbuf.Reset()\n\trequire.NoError(t, dir.WriteFile(\"1.6.sql\", []byte(\"create table t1_6(c int);\")))\n\tsum, err = dir.Checksum()\n\trequire.NoError(t, err)\n\trequire.NoError(t, migrate.WriteSumFile(dir, sum))\n\treport, err = rr.Report(ctx)\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))\n\trequire.Equal(t, `Migration Status: PENDING\n  -- Current Version: 2\n  -- Next Version:    UNKNOWN\n  -- Executed Files:  2\n  -- Pending Files:   2 (out of order)\n\n  ERROR: migration files 1.5.sql, 1.6.sql were added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error\n`, buf.String())\n\n\t// A mix of pending and out of order files.\n\tbuf.Reset()\n\trequire.NoError(t, dir.WriteFile(\"3.sql\", []byte(\"create table t3(c int);\")))\n\tsum, err = dir.Checksum()\n\trequire.NoError(t, err)\n\trequire.NoError(t, migrate.WriteSumFile(dir, sum))\n\treport, err = rr.Report(ctx)\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmdlog.MigrateStatusTemplate.Execute(&buf, report))\n\trequire.Equal(t, `Migration Status: PENDING\n  -- Current Version: 2\n  -- Next Version:    UNKNOWN\n  -- Executed Files:  2\n  -- Pending Files:   3 (2 out of order)\n\n  ERROR: migration files 1.5.sql, 1.6.sql were added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error\n`, buf.String())\n}\n\nfunc TestWarnOnce(t *testing.T) {\n\tb := &strings.Builder{}\n\trequire.NoError(t, cmdlog.WarnOnce(b, \"one\"))\n\trequire.NoError(t, cmdlog.WarnOnce(b, \"two\"))\n\trequire.Equal(t, \"one\", b.String())\n\n\tvar wg sync.WaitGroup\n\tb = &strings.Builder{}\n\twg.Add(5)\n\tfor i := 0; i < 5; i++ {\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\trequire.NoError(t, cmdlog.WarnOnce(b, \"one\"))\n\t\t}()\n\t}\n\twg.Wait()\n\trequire.Equal(t, \"one\", b.String())\n\n\t// Ensure the type is not assignable.\n\trequire.Panics(t, func() {\n\t\tvar m sync.Map\n\t\tm.LoadOrStore(unassignable{}, \"text\")\n\t})\n\tb.Reset()\n\trequire.NoError(t, cmdlog.WarnOnce(unassignable{Writer: b}, \"done\"))\n\trequire.Equal(t, \"done\", b.String())\n}\n\ntype unassignable struct {\n\t_ func()\n\tio.Writer\n}\n\nfunc (a unassignable) Write(p []byte) (n int, err error) { return a.Writer.Write(p) }\n"
  },
  {
    "path": "cmd/atlas/internal/cmdstate/cmdstate.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdstate\n\nimport (\n\t\"encoding/json\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/mitchellh/go-homedir\"\n)\n\n// DefaultDir is the directory where CLI state is stored.\nconst DefaultDir = \"~/.atlas\"\n\n// File is a state file for the given type.\ntype File[T any] struct {\n\t// Dir where the file is stored. If empty, DefaultDir is used.\n\tDir string\n\t// Name of the file. Suffixed with .json.\n\tName string\n}\n\n// Read reads the value from the file system.\nfunc (f File[T]) Read() (v T, err error) {\n\tpath, err := f.Path()\n\tif err != nil {\n\t\treturn v, err\n\t}\n\tswitch buf, err := os.ReadFile(path); {\n\tcase os.IsNotExist(err):\n\t\treturn newT(v), nil\n\tcase err != nil:\n\t\treturn v, err\n\tdefault:\n\t\terr = json.Unmarshal(buf, &v)\n\t\treturn v, err\n\t}\n}\n\n// Write writes the value to the file system.\nfunc (f File[T]) Write(t T) error {\n\tbuf, err := json.Marshal(t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tpath, err := f.Path()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {\n\t\treturn err\n\t}\n\treturn os.WriteFile(path, buf, 0666)\n}\n\n// Path returns the path to the file.\nfunc (f File[T]) Path() (string, error) {\n\tname := f.Name\n\tif filepath.Ext(name) == \"\" {\n\t\tname += \".json\"\n\t}\n\tif f.Dir != \"\" {\n\t\treturn filepath.Join(f.Dir, name), nil\n\t}\n\tpath, err := homedir.Expand(filepath.Join(DefaultDir, name))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn path, nil\n}\n\n// newT ensures the type is initialized.\nfunc newT[T any](t T) T {\n\tif rt := reflect.TypeOf(t); rt.Kind() == reflect.Ptr {\n\t\treturn reflect.New(rt.Elem()).Interface().(T)\n\t}\n\treturn t\n}\n\n// muDisableCache ensures homedir.DisableCache is not changed concurrently on tests.\nvar muDisableCache sync.Mutex\n\n// TestingHome is a helper function for testing that\n// sets the HOME directory to a temporary directory.\nfunc TestingHome(t *testing.T) string {\n\tmuDisableCache.Lock()\n\thomedir.DisableCache = true\n\tt.Cleanup(func() {\n\t\thomedir.DisableCache = false\n\t\tmuDisableCache.Unlock()\n\t})\n\thome := t.TempDir()\n\tt.Setenv(\"HOME\", home)\n\treturn home\n}\n"
  },
  {
    "path": "cmd/atlas/internal/cmdstate/cmdstate_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage cmdstate_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdstate\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFile(t *testing.T) {\n\thomedir.DisableCache = true\n\tt.Cleanup(func() { homedir.DisableCache = false })\n\n\ttype T struct{ V string }\n\tf := cmdstate.File[T]{Name: \"test\", Dir: t.TempDir()}\n\tv, err := f.Read()\n\trequire.NoError(t, err)\n\trequire.Equal(t, T{}, v)\n\trequire.NoError(t, f.Write(T{V: \"v\"}))\n\tv, err = f.Read()\n\trequire.NoError(t, err)\n\trequire.Equal(t, T{V: \"v\"}, v)\n\n\thome := t.TempDir()\n\tt.Setenv(\"HOME\", home)\n\tf = cmdstate.File[T]{Name: \"t\"}\n\t_, err = f.Read()\n\trequire.NoError(t, err)\n\tdirs, err := os.ReadDir(home)\n\trequire.NoError(t, err)\n\trequire.Empty(t, dirs)\n\n\trequire.NoError(t, f.Write(T{V: \"v\"}))\n\tdirs, err = os.ReadDir(home)\n\trequire.NoError(t, err)\n\trequire.Len(t, dirs, 1)\n\trequire.Equal(t, \".atlas\", dirs[0].Name())\n\tdirs, err = os.ReadDir(filepath.Join(home, \".atlas\"))\n\trequire.NoError(t, err)\n\trequire.Len(t, dirs, 1)\n\trequire.Equal(t, \"t.json\", dirs[0].Name())\n\tv, err = f.Read()\n\trequire.NoError(t, err)\n\trequire.Equal(t, T{V: \"v\"}, v)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/docker/docker.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage docker\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/go-sql-driver/mysql\"\n)\n\nconst (\n\tpass          = \"pass\"\n\tpassSQLServer = \"P@ssw0rd0995\"\n)\n\ntype (\n\t// Config is used to configure container creation.\n\tConfig struct {\n\t\tdriver string   // driver to open connections with.\n\t\tsetup  []string // contains statements to execute once the service is up\n\t\t// User is the user to connect to the database.\n\t\tUser *url.Userinfo\n\t\t// Internal Port to expose and connect to.\n\t\tPort string\n\t\t// Image is the name of the image to pull and run.\n\t\tImage string\n\t\t// Env vars to pass to the docker container.\n\t\tEnv []string\n\t\t// Database name to create and connect on init.\n\t\tDatabase string\n\t\t// Out is a custom writer to send docker cli output to.\n\t\tOut io.Writer\n\t\t// ConnOptions allows configuring the underlying connection pool.\n\t\tConnOptions *ConnOptions\n\t}\n\t// A Container is an instance of a created container.\n\tContainer struct {\n\t\tConfig // Config used to create this container\n\t\t// ID of the container.\n\t\tID string\n\t\t// Port on the host this containers service is bound to.\n\t\tPort string\n\t}\n\t// ConnOptions allows configuring the underlying connection pool.\n\tConnOptions struct {\n\t\tMaxOpen     int\n\t\tMaxIdle     int\n\t\tMaxLifetime time.Duration\n\t\tMaxIdleTime time.Duration\n\t}\n\t// ConfigOption allows configuring Config with functional arguments.\n\tConfigOption func(*Config) error\n)\n\n// NewConfig returns a new config with the given options applied.\nfunc NewConfig(opts ...ConfigOption) (*Config, error) {\n\tc := &Config{Out: io.Discard}\n\tfor _, opt := range opts {\n\t\tif err := opt(c); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn c, nil\n}\n\n// Well-known DB drivers\nconst (\n\tDriverMySQL      = \"mysql\"\n\tDriverMariaDB    = \"mariadb\"\n\tDriverPostgres   = \"postgres\"\n\tDriverSQLServer  = \"sqlserver\"\n\tDriverClickHouse = \"clickhouse\"\n)\n\nconst (\n\tPostgresPostGIS  = \"postgis\"\n\tPostgresPGVector = \"pgvector\"\n)\n\n// FromURL parses a URL in the format of\n// \"docker://driver/tag[/dbname]\" and returns a Config.\nfunc FromURL(u *url.URL, opts ...ConfigOption) (*Config, error) {\n\tvar (\n\t\tparts  = strings.Split(strings.TrimPrefix(u.Path, \"/\"), \"/\")\n\t\tidxTag = len(parts) - 1\n\t\tdbName string\n\t)\n\t// Check if the last part is a tag or a database name.\n\tif idxTag > 0 && !strings.ContainsRune(parts[idxTag], ':') {\n\t\t// The last part is not a tag, so it must be a database name.\n\t\tdbName, idxTag = parts[idxTag], idxTag-1\n\t}\n\tvar baseOpts []ConfigOption\n\tvar tag string\n\t// Support docker+driver://<image>[:<tag>]\n\tdriver, customImage := strings.CutPrefix(u.Scheme, \"docker+\")\n\tif customImage {\n\t\t// The image is fully specified in the URL.\n\t\timg := path.Join(parts[:idxTag+1]...)\n\t\tif u.Host != \"\" && u.Host != \"_\" {\n\t\t\timg = path.Join(u.Host, img)\n\t\t}\n\t\tbaseOpts = append(baseOpts, Image(img))\n\t} else {\n\t\tdriver = u.Host\n\t\tif idxTag >= 0 {\n\t\t\ttag = parts[idxTag]\n\t\t}\n\t}\n\tvar (\n\t\terr error\n\t\tcfg *Config\n\t)\n\tswitch driver {\n\tcase DriverMySQL:\n\t\tif dbName != \"\" {\n\t\t\tbaseOpts = append(baseOpts,\n\t\t\t\tDatabase(dbName),\n\t\t\t\tEnv(\"MYSQL_DATABASE=\"+dbName),\n\t\t\t\tSetup(fmt.Sprintf(\"CREATE DATABASE IF NOT EXISTS `%s`\", dbName)),\n\t\t\t)\n\t\t}\n\t\tcfg, err = MySQL(tag, append(baseOpts, opts...)...)\n\tcase \"maria\":\n\t\tdriver = DriverMariaDB\n\t\tfallthrough\n\tcase DriverMariaDB:\n\t\tif dbName != \"\" {\n\t\t\tbaseOpts = append(baseOpts,\n\t\t\t\tDatabase(dbName),\n\t\t\t\tEnv(\"MYSQL_DATABASE=\"+dbName),\n\t\t\t\tSetup(fmt.Sprintf(\"CREATE DATABASE IF NOT EXISTS `%s`\", dbName)),\n\t\t\t)\n\t\t}\n\t\tcfg, err = MariaDB(tag, append(baseOpts, opts...)...)\n\tcase PostgresPostGIS:\n\t\tbaseOpts = append(baseOpts, Image(\n\t\t\tfmt.Sprintf(\"%[1]s/%[1]s:%[2]s\", PostgresPostGIS, tag),\n\t\t))\n\t\tif dbName != \"\" && dbName != \"postgres\" {\n\t\t\t// Create manually the PostgreSQL database instead of using the POSTGRES_DB because\n\t\t\t// PostGIS automatically creates and install the following extensions and schemas:\n\t\t\t// Schemas: tiger, tiger_data, topology.\n\t\t\t// Extensions: postgis, postgis_topology, postgis_tiger_geocoder.\n\t\t\tbaseOpts = append(\n\t\t\t\tbaseOpts, Database(dbName), Setup(fmt.Sprintf(\"CREATE DATABASE %q\", dbName)),\n\t\t\t)\n\t\t}\n\t\tdriver = DriverPostgres\n\t\tcfg, err = PostgreSQL(tag, append(baseOpts, opts...)...)\n\tcase PostgresPGVector:\n\t\tbaseOpts = append(baseOpts, Image(\n\t\t\tfmt.Sprintf(\"%[1]s/%[1]s:%[2]s\", PostgresPGVector, tag),\n\t\t))\n\t\tif dbName != \"\" {\n\t\t\tbaseOpts = append(baseOpts, Database(dbName), Env(\"POSTGRES_DB=\"+dbName))\n\t\t}\n\t\tdriver = DriverPostgres\n\t\tcfg, err = PostgreSQL(tag, append(baseOpts, opts...)...)\n\tcase DriverPostgres:\n\t\tif dbName != \"\" {\n\t\t\tbaseOpts = append(baseOpts, Database(dbName), Env(\"POSTGRES_DB=\"+dbName))\n\t\t}\n\t\tcfg, err = PostgreSQL(tag, append(baseOpts, opts...)...)\n\tcase DriverSQLServer:\n\t\tif dbName != \"\" && dbName != \"master\" {\n\t\t\tbaseOpts = append(baseOpts,\n\t\t\t\tDatabase(dbName),\n\t\t\t\tSetup(fmt.Sprintf(\"CREATE DATABASE [%s]\", dbName)),\n\t\t\t)\n\t\t}\n\t\tcfg, err = SQLServer(tag, append(baseOpts, opts...)...)\n\tcase DriverClickHouse:\n\t\tif dbName != \"\" {\n\t\t\tbaseOpts = append(baseOpts,\n\t\t\t\tDatabase(dbName),\n\t\t\t\tEnv(\"CLICKHOUSE_DB=\"+dbName),\n\t\t\t\tSetup(fmt.Sprintf(\"CREATE DATABASE IF NOT EXISTS `%s`\", dbName)),\n\t\t\t)\n\t\t}\n\t\tcfg, err = ClickHouse(tag, append(baseOpts, opts...)...)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported docker image %q\", driver)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcfg.driver = driver\n\treturn cfg, nil\n}\n\n// ImageURL returns the base URL for the given driver and image.\nfunc ImageURL(driver string, image string) (*url.URL, error) {\n\tswitch {\n\tcase driver == \"\" && image == \"\":\n\t\treturn nil, errors.New(\"driver and image cannot be empty\")\n\tcase driver == \"\":\n\t\treturn nil, errors.New(\"driver cannot be empty\")\n\tcase image == \"\":\n\t\treturn nil, errors.New(\"image cannot be empty\")\n\tdefault:\n\t\tu := &url.URL{Scheme: \"docker+\" + driver, Host: \"_\", Path: image}\n\t\tif idx := strings.IndexByte(image, '/'); idx != -1 {\n\t\t\tu.Host, u.Path = image[:idx], image[idx+1:]\n\t\t}\n\t\treturn u, nil\n\t}\n}\n\n// Atlas DockerHub user contains the MySQL\n// and MariaDB images with faster boot times.\nconst hubUser = \"arigaio\"\n\n// MySQL returns a new Config for a MySQL image.\nfunc MySQL(version string, opts ...ConfigOption) (*Config, error) {\n\treturn NewConfig(\n\t\tappend(\n\t\t\t[]ConfigOption{\n\t\t\t\tImage(hubUser, \"mysql:\"+version),\n\t\t\t\tUserinfo(url.UserPassword(\"root\", pass)),\n\t\t\t\tPort(\"3306\"),\n\t\t\t\tEnv(\"MYSQL_ROOT_PASSWORD=\" + pass),\n\t\t\t},\n\t\t\topts...,\n\t\t)...,\n\t)\n}\n\n// MariaDB returns a new Config for a MariaDB image.\nfunc MariaDB(version string, opts ...ConfigOption) (*Config, error) {\n\treturn MySQL(version, append([]ConfigOption{Image(hubUser, \"mariadb:\"+version)}, opts...)...)\n}\n\n// PostgreSQL returns a new Config for a PostgreSQL image.\nfunc PostgreSQL(version string, opts ...ConfigOption) (*Config, error) {\n\treturn NewConfig(\n\t\tappend(\n\t\t\t[]ConfigOption{\n\t\t\t\tImage(\"postgres:\" + version),\n\t\t\t\tUserinfo(url.UserPassword(\"postgres\", pass)),\n\t\t\t\tPort(\"5432\"),\n\t\t\t\tDatabase(\"postgres\"),\n\t\t\t\tEnv(\"POSTGRES_PASSWORD=\" + pass),\n\t\t\t},\n\t\t\topts...,\n\t\t)...,\n\t)\n}\n\n// SQLServer returns a new Config for a SQLServer image.\nfunc SQLServer(version string, opts ...ConfigOption) (*Config, error) {\n\treturn NewConfig(\n\t\tappend(\n\t\t\t[]ConfigOption{\n\t\t\t\tImage(\"mcr.microsoft.com/mssql/server:\" + version),\n\t\t\t\tUserinfo(url.UserPassword(\"sa\", passSQLServer)),\n\t\t\t\tPort(\"1433\"),\n\t\t\t\tDatabase(\"master\"),\n\t\t\t\tEnv(\n\t\t\t\t\t\"ACCEPT_EULA=Y\",\n\t\t\t\t\t\"MSSQL_PID=Developer\",\n\t\t\t\t\t\"MSSQL_SA_PASSWORD=\"+passSQLServer,\n\t\t\t\t),\n\t\t\t},\n\t\t\topts...,\n\t\t)...,\n\t)\n}\n\n// ClickHouse returns a new Config for a ClickHouse image.\nfunc ClickHouse(version string, opts ...ConfigOption) (*Config, error) {\n\treturn NewConfig(\n\t\tappend(\n\t\t\t[]ConfigOption{\n\t\t\t\tImage(\"clickhouse/clickhouse-server:\" + version),\n\t\t\t\tUserinfo(url.UserPassword(\"default\", pass)),\n\t\t\t\tPort(\"9000\"),\n\t\t\t\tEnv(\"CLICKHOUSE_PASSWORD=\" + pass),\n\t\t\t},\n\t\t\topts...,\n\t\t)...,\n\t)\n}\n\n// Image sets the docker image to use. For example:\n//\n//\tImage(\"mysql\")\n//\tImage(\"arigaio\", \"mysql\")\n//\tImage(\"postgres:13\")\nfunc Image(parts ...string) ConfigOption {\n\treturn func(c *Config) error {\n\t\tif len(parts) == 0 || len(parts) > 2 {\n\t\t\treturn errors.New(\"image path must be in the format of 'image' or 'user/image'\")\n\t\t}\n\t\tc.Image = strings.TrimSuffix(path.Join(parts...), \":\")\n\t\treturn nil\n\t}\n}\n\n// Port sets the port the container services exposes. For example:\n//\n//\tPort(\"3306\")\n//\tPort(\"5432\")\nfunc Port(p string) ConfigOption {\n\treturn func(c *Config) error {\n\t\tc.Port = p\n\t\treturn nil\n\t}\n}\n\n// Env sets the environment variables to pass to the container. For example:\n//\n//\tConfig(Image(\"mysql\"), Env(\"MYSQL_ROOT_PASSWORD=password\"))\n//\tConfig(Image(\"postgres\"), Env(\"MYSQL_ROOT_PASSWORD=password\"))\nfunc Env(env ...string) ConfigOption {\n\treturn func(c *Config) error {\n\t\tc.Env = append(c.Env, env...)\n\t\treturn nil\n\t}\n}\n\n// Database sets the database name to connect to. For example:\n//\n//\tDatabase(\"test\")\nfunc Database(name string) ConfigOption {\n\treturn func(c *Config) error {\n\t\tc.Database = name\n\t\treturn nil\n\t}\n}\n\n// Userinfo sets the user to connect to the database. For example:\n//\n//\tUserinfo(url.User(\"root\", \"pass\"))\nfunc Userinfo(u *url.Userinfo) ConfigOption {\n\treturn func(c *Config) error {\n\t\tc.User = u\n\t\treturn nil\n\t}\n}\n\n// Out sets an io.Writer to use when running docker commands. For example:\n//\n//\tbuf := new(bytes.Buffer)\n//\tNewConfig(Out(buf))\nfunc Out(w io.Writer) ConfigOption {\n\treturn func(c *Config) error {\n\t\tc.Out = w\n\t\treturn nil\n\t}\n}\n\n// Setup adds statements to execute once the service is ready. For example:\n//\n//\tsetup(\"CREATE DATABASE IF NOT EXISTS test\")\n//\tsetup(\"DROP SCHEMA IF EXISTS public CASCADE\")\nfunc Setup(s ...string) ConfigOption {\n\treturn func(c *Config) error {\n\t\tc.setup = append(c.setup, s...)\n\t\treturn nil\n\t}\n}\n\n// Conn sets the config connection configuration.\nfunc Conn(s *ConnOptions) ConfigOption {\n\treturn func(c *Config) error {\n\t\tc.ConnOptions = s\n\t\treturn nil\n\t}\n}\n\n// Run pulls and starts a new docker container from the Config.\nfunc (c *Config) Run(ctx context.Context) (*Container, error) {\n\t// Make sure the configuration is not missing critical values.\n\tif err := c.validate(); err != nil {\n\t\treturn nil, err\n\t}\n\t// Get a free host TCP port the container can bind its exposed service port on.\n\tp, err := freePort()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting open port: %w\", err)\n\t}\n\t// Run the container.\n\targs := []string{\"docker\", \"run\", \"--rm\", \"--detach\"}\n\tfor _, e := range c.Env {\n\t\targs = append(args, \"-e\", e)\n\t}\n\targs = append(args, \"-p\", fmt.Sprintf(\"%s:%s\", p, c.Port), c.Image)\n\tcmd := exec.CommandContext(ctx, args[0], args[1:]...) //nolint:gosec\n\tstdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}\n\tcmd.Stdout, cmd.Stderr = io.MultiWriter(c.Out, stdout), stderr\n\tif err := cmd.Run(); err != nil {\n\t\tif stderr.Len() > 0 {\n\t\t\terr = errors.New(strings.TrimSpace(stderr.String()))\n\t\t}\n\t\treturn nil, err\n\t}\n\treturn &Container{\n\t\tConfig: *c,\n\t\tID:     strings.TrimSpace(stdout.String()),\n\t\tPort:   p,\n\t}, nil\n}\n\n// Close stops and removes this container.\nfunc (c *Container) Close() error {\n\treturn exec.Command(\"docker\", \"kill\", c.ID).Run() //nolint:gosec\n}\n\n// Wait waits for this container to be ready.\nfunc (c *Container) Wait(ctx context.Context, timeout time.Duration) error {\n\tfmt.Fprintln(c.Out, \"Waiting for service to be ready ... \")\n\tmysql.SetLogger(log.New(io.Discard, \"\", 1))\n\tdefer mysql.SetLogger(log.New(os.Stderr, \"[mysql] \", log.Ldate|log.Ltime|log.Lshortfile))\n\tif timeout > time.Minute {\n\t\ttimeout = time.Minute\n\t}\n\tvar (\n\t\tdone   = time.After(timeout)\n\t\tu, err = c.URL()\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\tpingURL := c.PingURL(*u)\n\tfor {\n\t\tselect {\n\t\tcase <-time.After(100 * time.Millisecond):\n\t\t\tvar client *sqlclient.Client\n\t\t\t// Ping against the root connection.\n\t\t\tclient, err = sqlclient.Open(ctx, pingURL)\n\t\t\tif err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tdb := client.DB\n\t\t\tif err = db.PingContext(ctx); err != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, s := range c.setup {\n\t\t\t\tif _, err := db.ExecContext(ctx, s); err != nil {\n\t\t\t\t\terr = errors.Join(err, db.Close())\n\t\t\t\t\treturn fmt.Errorf(\"%q: %w\", s, err)\n\t\t\t\t}\n\t\t\t}\n\t\t\t_ = db.Close()\n\t\t\tfmt.Fprintln(c.Out, \"Service is ready to connect!\")\n\t\t\treturn nil\n\t\tcase <-ctx.Done():\n\t\t\treturn ctx.Err()\n\t\tcase <-done:\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"timeout: %w\", err)\n\t\t\t}\n\t\t\treturn errors.New(\"timeout\")\n\t\t}\n\t}\n}\n\n// URL returns a URL to connect to the Container.\nfunc (c *Container) URL() (*url.URL, error) {\n\thost := \"localhost\"\n\t// Check if the DOCKER_HOST env var is set.\n\t// If it is, use the host from the URL.\n\tif h := os.Getenv(\"DOCKER_HOST\"); h != \"\" {\n\t\tu, err := url.Parse(h)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// Only use the hostname if the scheme is tcp or ssh.\n\t\t// For unix sockets, the hostname is localhost.\n\t\t// See https://docs.docker.com/reference/cli/docker/#host\n\t\tif u.Scheme == \"tcp\" || u.Scheme == \"ssh\" {\n\t\t\thost = u.Hostname()\n\t\t}\n\t}\n\tu := &url.URL{\n\t\tScheme: c.driver,\n\t\tUser:   c.User,\n\t\tHost:   fmt.Sprintf(\"%s:%s\", host, c.Port),\n\t}\n\tswitch c.driver {\n\tcase DriverSQLServer:\n\t\tq := u.Query()\n\t\tq.Set(\"database\", c.Database)\n\t\tu.RawQuery = q.Encode()\n\tcase DriverPostgres:\n\t\tq := u.Query()\n\t\tq.Set(\"sslmode\", \"disable\")\n\t\tu.Path, u.RawQuery = c.Database, q.Encode()\n\t\tif u.Path == \"\" {\n\t\t\tu.Path = \"/\"\n\t\t}\n\tcase DriverMySQL, DriverMariaDB, DriverClickHouse: // MySQL compatible\n\t\tu.Path = c.Database\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown driver: %q\", c.driver)\n\t}\n\treturn u, nil\n}\n\n// PingURL returns a URL to ping the Container.\nfunc (c *Container) PingURL(u url.URL) string {\n\tswitch c.driver {\n\tcase DriverSQLServer:\n\t\tq := u.Query()\n\t\tq.Del(\"database\")\n\t\tu.RawQuery = q.Encode()\n\t\treturn u.String()\n\tdefault:\n\t\tu.Path = \"/\"\n\t\treturn u.String()\n\t}\n}\n\n// validate that no empty values are given.\nfunc (c *Config) validate() error {\n\tif c == nil || c.Image == \"\" || c.Port == \"\" || c.Out == nil {\n\t\treturn fmt.Errorf(\"invalid configuration %#v\", c)\n\t}\n\treturn nil\n}\n\nfunc freePort() (string, error) {\n\ta, err := net.ResolveTCPAddr(\"tcp\", \":0\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tl, err := net.ListenTCP(\"tcp\", a)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif err := l.Close(); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn strconv.Itoa(l.Addr().(*net.TCPAddr).Port), nil\n}\n\nfunc init() {\n\tsqlclient.Register(\n\t\t\"docker\",\n\t\tsqlclient.OpenerFunc(Open),\n\t\tsqlclient.RegisterFlavours(\n\t\t\t\"docker+postgres\",\n\t\t\t\"docker+mysql\", \"docker+maria\", \"docker+mariadb\", \"docker+clickhouse\",\n\t\t\t\"docker+sqlserver\",\n\t\t),\n\t)\n}\n\n// Open a new docker client.\nfunc Open(ctx context.Context, u *url.URL) (client *sqlclient.Client, err error) {\n\treturn OpenWithOpts(ctx, u)\n}\n\n// OpenWithOpts open a new docker client\nfunc OpenWithOpts(ctx context.Context, u *url.URL, opts ...ConfigOption) (client *sqlclient.Client, err error) {\n\tcfg, err := FromURL(u, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tqr := u.Query()\n\tif qr.Has(\"v\") || qr.Has(\"verbose\") {\n\t\tif err := Out(os.Stdout)(cfg); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tqr.Del(\"v\")\n\t\tqr.Del(\"verbose\")\n\t}\n\tc, err := cfg.Run(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tif cerr := c.Close(); err != nil {\n\t\t\t\terr = fmt.Errorf(\"%w: %v\", err, cerr)\n\t\t\t}\n\t\t}\n\t}()\n\tif err = c.Wait(ctx, time.Minute); err != nil {\n\t\treturn nil, err\n\t}\n\tu1, err := c.URL()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor k, v := range u1.Query() {\n\t\tqr[k] = v\n\t}\n\tu1.RawQuery = qr.Encode()\n\tif client, err = sqlclient.Open(ctx, u1.String()); err != nil {\n\t\treturn nil, err\n\t}\n\tclient.Ephemeral = true\n\tif s := c.ConnOptions; s != nil {\n\t\tif s.MaxOpen > 0 {\n\t\t\tclient.DB.SetMaxOpenConns(s.MaxOpen)\n\t\t}\n\t\tif s.MaxIdle > 0 {\n\t\t\tclient.DB.SetMaxIdleConns(s.MaxIdle)\n\t\t}\n\t\tif s.MaxLifetime > 0 {\n\t\t\tclient.DB.SetConnMaxLifetime(s.MaxLifetime)\n\t\t}\n\t\tif s.MaxIdleTime > 0 {\n\t\t\tclient.DB.SetConnMaxIdleTime(s.MaxIdleTime)\n\t\t}\n\t}\n\tclient.AddClosers(c)\n\treturn client, nil\n}\n"
  },
  {
    "path": "cmd/atlas/internal/docker/docker_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage docker\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDockerConfig(t *testing.T) {\n\tctx := context.Background()\n\n\t// invalid config\n\t_, err := (&Config{}).Run(ctx)\n\trequire.Error(t, err)\n\n\t// MySQL\n\tcfg, err := MySQL(\"latest\", Out(io.Discard))\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tImage: \"arigaio/mysql:latest\",\n\t\tUser:  url.UserPassword(\"root\", pass),\n\t\tEnv:   []string{\"MYSQL_ROOT_PASSWORD=pass\"},\n\t\tPort:  \"3306\",\n\t\tOut:   io.Discard,\n\t}, cfg)\n\n\t// MariaDB\n\tcfg, err = MariaDB(\"latest\", Out(io.Discard))\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tImage: \"arigaio/mariadb:latest\",\n\t\tUser:  url.UserPassword(\"root\", pass),\n\t\tEnv:   []string{\"MYSQL_ROOT_PASSWORD=pass\"},\n\t\tPort:  \"3306\",\n\t\tOut:   io.Discard,\n\t}, cfg)\n\n\t// PostgreSQL\n\tcfg, err = PostgreSQL(\"latest\", Out(io.Discard))\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tImage:    \"postgres:latest\",\n\t\tUser:     url.UserPassword(\"postgres\", pass),\n\t\tEnv:      []string{\"POSTGRES_PASSWORD=pass\"},\n\t\tDatabase: \"postgres\",\n\t\tPort:     \"5432\",\n\t\tOut:      io.Discard,\n\t}, cfg)\n\n\t// SQL Server\n\tcfg, err = SQLServer(\"2022-latest\", Out(io.Discard))\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tImage:    \"mcr.microsoft.com/mssql/server:2022-latest\",\n\t\tUser:     url.UserPassword(\"sa\", passSQLServer),\n\t\tPort:     \"1433\",\n\t\tDatabase: \"master\",\n\t\tOut:      io.Discard,\n\t\tEnv: []string{\n\t\t\t\"ACCEPT_EULA=Y\",\n\t\t\t\"MSSQL_PID=Developer\",\n\t\t\t\"MSSQL_SA_PASSWORD=\" + passSQLServer,\n\t\t},\n\t}, cfg)\n\n\t// ClickHouse\n\tcfg, err = ClickHouse(\"23.11\", Out(io.Discard))\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tImage: \"clickhouse/clickhouse-server:23.11\",\n\t\tUser:  url.UserPassword(\"default\", pass),\n\t\tPort:  \"9000\",\n\t\tOut:   io.Discard,\n\t\tEnv: []string{\n\t\t\t\"CLICKHOUSE_PASSWORD=pass\",\n\t\t},\n\t}, cfg)\n}\n\nfunc TestFromURL(t *testing.T) {\n\tu, err := url.Parse(\"docker://mysql\")\n\trequire.NoError(t, err)\n\tcfg, err := FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver: \"mysql\",\n\t\tImage:  \"arigaio/mysql\",\n\t\tUser:   url.UserPassword(\"root\", pass),\n\t\tEnv:    []string{\"MYSQL_ROOT_PASSWORD=pass\"},\n\t\tPort:   \"3306\",\n\t\tOut:    io.Discard,\n\t}, cfg)\n\n\tu, err = url.Parse(\"docker://mysql/8\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver: \"mysql\",\n\t\tImage:  \"arigaio/mysql:8\",\n\t\tUser:   url.UserPassword(\"root\", pass),\n\t\tEnv:    []string{\"MYSQL_ROOT_PASSWORD=pass\"},\n\t\tPort:   \"3306\",\n\t\tOut:    io.Discard,\n\t}, cfg)\n\n\tu, err = url.Parse(\"docker://mysql/latest/test\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver:   \"mysql\",\n\t\tImage:    \"arigaio/mysql:latest\",\n\t\tDatabase: \"test\",\n\t\tEnv:      []string{\"MYSQL_ROOT_PASSWORD=pass\", \"MYSQL_DATABASE=test\"},\n\t\tUser:     url.UserPassword(\"root\", pass),\n\t\tPort:     \"3306\",\n\t\tOut:      io.Discard,\n\t\tsetup:    []string{\"CREATE DATABASE IF NOT EXISTS `test`\"},\n\t}, cfg)\n\n\tu, err = url.Parse(\"docker://postgres/13\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver:   \"postgres\",\n\t\tImage:    \"postgres:13\",\n\t\tDatabase: \"postgres\",\n\t\tEnv:      []string{\"POSTGRES_PASSWORD=pass\"},\n\t\tUser:     url.UserPassword(\"postgres\", pass),\n\t\tPort:     \"5432\",\n\t\tOut:      io.Discard,\n\t}, cfg)\n\n\t// PostGIS.\n\tu, err = url.Parse(\"docker://postgis/14-3.4\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver:   \"postgres\",\n\t\tImage:    \"postgis/postgis:14-3.4\",\n\t\tDatabase: \"postgres\",\n\t\tEnv:      []string{\"POSTGRES_PASSWORD=pass\"},\n\t\tUser:     url.UserPassword(\"postgres\", pass),\n\t\tPort:     \"5432\",\n\t\tOut:      io.Discard,\n\t}, cfg)\n\n\tu, err = url.Parse(\"docker://postgis/14-3.4/dev\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver:   \"postgres\",\n\t\tImage:    \"postgis/postgis:14-3.4\",\n\t\tDatabase: \"dev\",\n\t\tEnv:      []string{\"POSTGRES_PASSWORD=pass\"},\n\t\tUser:     url.UserPassword(\"postgres\", pass),\n\t\tPort:     \"5432\",\n\t\tOut:      io.Discard,\n\t\tsetup:    []string{`CREATE DATABASE \"dev\"`},\n\t}, cfg)\n\n\t// PGVector.\n\tu, err = url.Parse(\"docker://pgvector/pg17\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver:   \"postgres\",\n\t\tImage:    \"pgvector/pgvector:pg17\",\n\t\tDatabase: \"postgres\",\n\t\tEnv:      []string{\"POSTGRES_PASSWORD=pass\"},\n\t\tUser:     url.UserPassword(\"postgres\", pass),\n\t\tPort:     \"5432\",\n\t\tOut:      io.Discard,\n\t}, cfg)\n\n\tu, err = url.Parse(\"docker://pgvector/pg17/dev\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver:   \"postgres\",\n\t\tImage:    \"pgvector/pgvector:pg17\",\n\t\tDatabase: \"dev\",\n\t\tEnv:      []string{\"POSTGRES_PASSWORD=pass\", \"POSTGRES_DB=dev\"},\n\t\tUser:     url.UserPassword(\"postgres\", pass),\n\t\tPort:     \"5432\",\n\t\tOut:      io.Discard,\n\t}, cfg)\n\n\t// SQL Server\n\tu, err = url.Parse(\"docker://sqlserver\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver:   \"sqlserver\",\n\t\tImage:    \"mcr.microsoft.com/mssql/server\",\n\t\tDatabase: \"master\",\n\t\tUser:     url.UserPassword(\"sa\", passSQLServer),\n\t\tPort:     \"1433\",\n\t\tOut:      io.Discard,\n\t\tEnv: []string{\n\t\t\t\"ACCEPT_EULA=Y\",\n\t\t\t\"MSSQL_PID=Developer\",\n\t\t\t\"MSSQL_SA_PASSWORD=\" + passSQLServer,\n\t\t},\n\t}, cfg)\n\n\tu, err = url.Parse(\"docker://sqlserver/2022-latest\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver:   \"sqlserver\",\n\t\tImage:    \"mcr.microsoft.com/mssql/server:2022-latest\",\n\t\tDatabase: \"master\",\n\t\tUser:     url.UserPassword(\"sa\", passSQLServer),\n\t\tPort:     \"1433\",\n\t\tOut:      io.Discard,\n\t\tEnv: []string{\n\t\t\t\"ACCEPT_EULA=Y\",\n\t\t\t\"MSSQL_PID=Developer\",\n\t\t\t\"MSSQL_SA_PASSWORD=\" + passSQLServer,\n\t\t},\n\t}, cfg)\n\n\tu, err = url.Parse(\"docker://sqlserver/2019-latest/foo\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver:   \"sqlserver\",\n\t\tsetup:    []string{\"CREATE DATABASE [foo]\"},\n\t\tImage:    \"mcr.microsoft.com/mssql/server:2019-latest\",\n\t\tDatabase: \"foo\",\n\t\tUser:     url.UserPassword(\"sa\", passSQLServer),\n\t\tPort:     \"1433\",\n\t\tOut:      io.Discard,\n\t\tEnv: []string{\n\t\t\t\"ACCEPT_EULA=Y\",\n\t\t\t\"MSSQL_PID=Developer\",\n\t\t\t\"MSSQL_SA_PASSWORD=\" + passSQLServer,\n\t\t},\n\t}, cfg)\n\n\t// Azure SQL Edge\n\tu, err = url.Parse(\"docker+sqlserver://mcr.microsoft.com/azure-sql-edge:1.0.7/foo\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver:   \"sqlserver\",\n\t\tsetup:    []string{\"CREATE DATABASE [foo]\"},\n\t\tImage:    \"mcr.microsoft.com/azure-sql-edge:1.0.7\",\n\t\tDatabase: \"foo\",\n\t\tUser:     url.UserPassword(\"sa\", passSQLServer),\n\t\tPort:     \"1433\",\n\t\tOut:      io.Discard,\n\t\tEnv: []string{\n\t\t\t\"ACCEPT_EULA=Y\",\n\t\t\t\"MSSQL_PID=Developer\",\n\t\t\t\"MSSQL_SA_PASSWORD=\" + passSQLServer,\n\t\t},\n\t}, cfg)\n\n\t// ClickHouse\n\tu, err = url.Parse(\"docker://clickhouse\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver: \"clickhouse\",\n\t\tImage:  \"clickhouse/clickhouse-server\",\n\t\tEnv:    []string{\"CLICKHOUSE_PASSWORD=pass\"},\n\t\tUser:   url.UserPassword(\"default\", pass),\n\t\tPort:   \"9000\",\n\t\tOut:    io.Discard,\n\t}, cfg)\n\n\t// ClickHouse with tag\n\tu, err = url.Parse(\"docker://clickhouse/23.11\")\n\trequire.NoError(t, err)\n\tcfg, err = FromURL(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &Config{\n\t\tdriver: \"clickhouse\",\n\t\tImage:  \"clickhouse/clickhouse-server:23.11\",\n\t\tUser:   url.UserPassword(\"default\", pass),\n\t\tEnv:    []string{\"CLICKHOUSE_PASSWORD=pass\"},\n\t\tPort:   \"9000\",\n\t\tOut:    io.Discard,\n\t}, cfg)\n}\n\nfunc TestFromURL_CustomImage(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\turl, image, db, dialect string\n\t}{\n\t\t// PostgreSQL (local and official images).\n\t\t{\n\t\t\turl:     \"docker+postgres://local\",\n\t\t\timage:   \"local\",\n\t\t\tdb:      \"postgres\",\n\t\t\tdialect: \"postgres\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+postgres://_/local/dev\",\n\t\t\timage:   \"local\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"postgres\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+postgres:///local:tag/dev\",\n\t\t\timage:   \"local:tag\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"postgres\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+postgres://postgres\",\n\t\t\timage:   \"postgres\",\n\t\t\tdb:      \"postgres\",\n\t\t\tdialect: \"postgres\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+postgres://_/postgres/dev\",\n\t\t\timage:   \"postgres\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"postgres\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+postgres:///postgres:16/dev\",\n\t\t\timage:   \"postgres:16\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"postgres\",\n\t\t},\n\t\t// User images.\n\t\t{\n\t\t\turl:     \"docker+postgres://postgis/postgis:16\",\n\t\t\timage:   \"postgis/postgis:16\",\n\t\t\tdb:      \"postgres\",\n\t\t\tdialect: \"postgres\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+postgres://postgis/postgis:16/dev\",\n\t\t\timage:   \"postgis/postgis:16\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"postgres\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+postgres://ghcr.io/namespace/image:tag\",\n\t\t\timage:   \"ghcr.io/namespace/image:tag\",\n\t\t\tdb:      \"postgres\",\n\t\t\tdialect: \"postgres\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+postgres://ghcr.io/namespace/image:tag/dev\",\n\t\t\timage:   \"ghcr.io/namespace/image:tag\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"postgres\",\n\t\t},\n\t\t// MySQL.\n\t\t{\n\t\t\turl:     \"docker+mysql://local\",\n\t\t\timage:   \"local\",\n\t\t\tdialect: \"mysql\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+mysql:///local/dev\",\n\t\t\timage:   \"local\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"mysql\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+mysql://user/image\",\n\t\t\timage:   \"user/image\",\n\t\t\tdialect: \"mysql\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+mysql://user/image:tag/dev\",\n\t\t\timage:   \"user/image:tag\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"mysql\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+mysql://_/mariadb:latest/dev\",\n\t\t\timage:   \"mariadb:latest\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"mysql\",\n\t\t},\n\t\t// SQL Server.\n\t\t{\n\t\t\turl:     \"docker+sqlserver://mcr.microsoft.com/mssql/server:2022-latest\",\n\t\t\timage:   \"mcr.microsoft.com/mssql/server:2022-latest\",\n\t\t\tdb:      \"master\",\n\t\t\tdialect: \"sqlserver\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+sqlserver://mcr.microsoft.com/mssql/server:2022-latest/dev\",\n\t\t\timage:   \"mcr.microsoft.com/mssql/server:2022-latest\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"sqlserver\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+sqlserver://mcr.microsoft.com/mssql/server:latest\",\n\t\t\timage:   \"mcr.microsoft.com/mssql/server:latest\",\n\t\t\tdb:      \"master\",\n\t\t\tdialect: \"sqlserver\",\n\t\t},\n\t\t// ClickHouse.\n\t\t{\n\t\t\turl:     \"docker+clickhouse://clickhouse/clickhouse-server:23.11\",\n\t\t\timage:   \"clickhouse/clickhouse-server:23.11\",\n\t\t\tdialect: \"clickhouse\",\n\t\t},\n\t\t{\n\t\t\turl:     \"docker+clickhouse://clickhouse/clickhouse-server:23.11/dev\",\n\t\t\timage:   \"clickhouse/clickhouse-server:23.11\",\n\t\t\tdb:      \"dev\",\n\t\t\tdialect: \"clickhouse\",\n\t\t},\n\t} {\n\t\tu, err := url.Parse(tt.url)\n\t\trequire.NoError(t, err)\n\t\tcfg, err := FromURL(u)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, tt.image, cfg.Image)\n\t\trequire.Equal(t, tt.db, cfg.Database)\n\t\trequire.Equal(t, tt.dialect, cfg.driver)\n\t}\n}\n\nfunc TestImageURL(t *testing.T) {\n\tfor img, u := range map[string]string{\n\t\t\"postgres:15\":                    \"docker+postgres://_/postgres:15\",\n\t\t\"postgres\":                       \"docker+postgres://_/postgres\",\n\t\t\"postgis/postgis:14-3.4\":         \"docker+postgres://postgis/postgis:14-3.4\",\n\t\t\"ghcr.io/namespace/postgres:tag\": \"docker+postgres://ghcr.io/namespace/postgres:tag\",\n\t} {\n\t\tgot, err := ImageURL(DriverPostgres, img)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, u, got.String())\n\t}\n\tfor img, u := range map[string]string{\n\t\t\"mcr.microsoft.com/azure-sql-edge:1.0.7\":     \"docker+sqlserver://mcr.microsoft.com/azure-sql-edge:1.0.7\",\n\t\t\"mcr.microsoft.com/mssql/server:2022-latest\": \"docker+sqlserver://mcr.microsoft.com/mssql/server:2022-latest\",\n\t} {\n\t\tgot, err := ImageURL(DriverSQLServer, img)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, u, got.String())\n\t}\n}\n\nfunc TestContainerURL(t *testing.T) {\n\tc := &Container{\n\t\tConfig: Config{\n\t\t\tdriver: \"postgres\",\n\t\t\tUser:   url.UserPassword(\"postgres\", \"pass\"),\n\t\t},\n\t\tPort: \"5432\",\n\t}\n\tu, err := c.URL()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"postgres://postgres:pass@localhost:5432/?sslmode=disable\", u.String())\n\n\t// With DOCKER_HOST\n\tt.Setenv(\"DOCKER_HOST\", \"tcp://host.docker.internal:2375\")\n\tu, err = c.URL()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"postgres://postgres:pass@host.docker.internal:5432/?sslmode=disable\", u.String())\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/client.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/migrate\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"entgo.io/ent\"\n\t\"entgo.io/ent/dialect\"\n\t\"entgo.io/ent/dialect/sql\"\n\n\tstdsql \"database/sql\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/internal\"\n)\n\n// Client is the client that holds all ent builders.\ntype Client struct {\n\tconfig\n\t// Schema is the client for creating, migrating and dropping schema.\n\tSchema *migrate.Schema\n\t// Revision is the client for interacting with the Revision builders.\n\tRevision *RevisionClient\n}\n\n// NewClient creates a new client configured with the given options.\nfunc NewClient(opts ...Option) *Client {\n\tclient := &Client{config: newConfig(opts...)}\n\tclient.init()\n\treturn client\n}\n\nfunc (c *Client) init() {\n\tc.Schema = migrate.NewSchema(c.driver)\n\tc.Revision = NewRevisionClient(c.config)\n}\n\ntype (\n\t// config is the configuration for the client and its builder.\n\tconfig struct {\n\t\t// driver used for executing database requests.\n\t\tdriver dialect.Driver\n\t\t// debug enable a debug logging.\n\t\tdebug bool\n\t\t// log used for logging on debug mode.\n\t\tlog func(...any)\n\t\t// hooks to execute on mutations.\n\t\thooks *hooks\n\t\t// interceptors to execute on queries.\n\t\tinters *inters\n\t\t// schemaConfig contains alternative names for all tables.\n\t\tschemaConfig SchemaConfig\n\t}\n\t// Option function to configure the client.\n\tOption func(*config)\n)\n\n// newConfig creates a new config for the client.\nfunc newConfig(opts ...Option) config {\n\tcfg := config{log: log.Println, hooks: &hooks{}, inters: &inters{}}\n\tcfg.options(opts...)\n\treturn cfg\n}\n\n// options applies the options on the config object.\nfunc (c *config) options(opts ...Option) {\n\tfor _, opt := range opts {\n\t\topt(c)\n\t}\n\tif c.debug {\n\t\tc.driver = dialect.Debug(c.driver, c.log)\n\t}\n}\n\n// Debug enables debug logging on the ent.Driver.\nfunc Debug() Option {\n\treturn func(c *config) {\n\t\tc.debug = true\n\t}\n}\n\n// Log sets the logging function for debug mode.\nfunc Log(fn func(...any)) Option {\n\treturn func(c *config) {\n\t\tc.log = fn\n\t}\n}\n\n// Driver configures the client driver.\nfunc Driver(driver dialect.Driver) Option {\n\treturn func(c *config) {\n\t\tc.driver = driver\n\t}\n}\n\n// Open opens a database/sql.DB specified by the driver name and\n// the data source name, and returns a new client attached to it.\n// Optional parameters can be added for configuring the client.\nfunc Open(driverName, dataSourceName string, options ...Option) (*Client, error) {\n\tswitch driverName {\n\tcase dialect.MySQL, dialect.Postgres, dialect.SQLite:\n\t\tdrv, err := sql.Open(driverName, dataSourceName)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn NewClient(append(options, Driver(drv))...), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported driver: %q\", driverName)\n\t}\n}\n\n// ErrTxStarted is returned when trying to start a new transaction from a transactional client.\nvar ErrTxStarted = errors.New(\"ent: cannot start a transaction within a transaction\")\n\n// Tx returns a new transactional client. The provided context\n// is used until the transaction is committed or rolled back.\nfunc (c *Client) Tx(ctx context.Context) (*Tx, error) {\n\tif _, ok := c.driver.(*txDriver); ok {\n\t\treturn nil, ErrTxStarted\n\t}\n\ttx, err := newTx(ctx, c.driver)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ent: starting a transaction: %w\", err)\n\t}\n\tcfg := c.config\n\tcfg.driver = tx\n\treturn &Tx{\n\t\tctx:      ctx,\n\t\tconfig:   cfg,\n\t\tRevision: NewRevisionClient(cfg),\n\t}, nil\n}\n\n// BeginTx returns a transactional client with specified options.\nfunc (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {\n\tif _, ok := c.driver.(*txDriver); ok {\n\t\treturn nil, errors.New(\"ent: cannot start a transaction within a transaction\")\n\t}\n\ttx, err := c.driver.(interface {\n\t\tBeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error)\n\t}).BeginTx(ctx, opts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"ent: starting a transaction: %w\", err)\n\t}\n\tcfg := c.config\n\tcfg.driver = &txDriver{tx: tx, drv: c.driver}\n\treturn &Tx{\n\t\tctx:      ctx,\n\t\tconfig:   cfg,\n\t\tRevision: NewRevisionClient(cfg),\n\t}, nil\n}\n\n// Debug returns a new debug-client. It's used to get verbose logging on specific operations.\n//\n//\tclient.Debug().\n//\t\tRevision.\n//\t\tQuery().\n//\t\tCount(ctx)\nfunc (c *Client) Debug() *Client {\n\tif c.debug {\n\t\treturn c\n\t}\n\tcfg := c.config\n\tcfg.driver = dialect.Debug(c.driver, c.log)\n\tclient := &Client{config: cfg}\n\tclient.init()\n\treturn client\n}\n\n// Close closes the database connection and prevents new queries from starting.\nfunc (c *Client) Close() error {\n\treturn c.driver.Close()\n}\n\n// Use adds the mutation hooks to all the entity clients.\n// In order to add hooks to a specific client, call: `client.Node.Use(...)`.\nfunc (c *Client) Use(hooks ...Hook) {\n\tc.Revision.Use(hooks...)\n}\n\n// Intercept adds the query interceptors to all the entity clients.\n// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`.\nfunc (c *Client) Intercept(interceptors ...Interceptor) {\n\tc.Revision.Intercept(interceptors...)\n}\n\n// Mutate implements the ent.Mutator interface.\nfunc (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {\n\tswitch m := m.(type) {\n\tcase *RevisionMutation:\n\t\treturn c.Revision.mutate(ctx, m)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"ent: unknown mutation type %T\", m)\n\t}\n}\n\n// RevisionClient is a client for the Revision schema.\ntype RevisionClient struct {\n\tconfig\n}\n\n// NewRevisionClient returns a client for the Revision from the given config.\nfunc NewRevisionClient(c config) *RevisionClient {\n\treturn &RevisionClient{config: c}\n}\n\n// Use adds a list of mutation hooks to the hooks stack.\n// A call to `Use(f, g, h)` equals to `revision.Hooks(f(g(h())))`.\nfunc (c *RevisionClient) Use(hooks ...Hook) {\n\tc.hooks.Revision = append(c.hooks.Revision, hooks...)\n}\n\n// Intercept adds a list of query interceptors to the interceptors stack.\n// A call to `Intercept(f, g, h)` equals to `revision.Intercept(f(g(h())))`.\nfunc (c *RevisionClient) Intercept(interceptors ...Interceptor) {\n\tc.inters.Revision = append(c.inters.Revision, interceptors...)\n}\n\n// Create returns a builder for creating a Revision entity.\nfunc (c *RevisionClient) Create() *RevisionCreate {\n\tmutation := newRevisionMutation(c.config, OpCreate)\n\treturn &RevisionCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}\n}\n\n// CreateBulk returns a builder for creating a bulk of Revision entities.\nfunc (c *RevisionClient) CreateBulk(builders ...*RevisionCreate) *RevisionCreateBulk {\n\treturn &RevisionCreateBulk{config: c.config, builders: builders}\n}\n\n// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates\n// a builder and applies setFunc on it.\nfunc (c *RevisionClient) MapCreateBulk(slice any, setFunc func(*RevisionCreate, int)) *RevisionCreateBulk {\n\trv := reflect.ValueOf(slice)\n\tif rv.Kind() != reflect.Slice {\n\t\treturn &RevisionCreateBulk{err: fmt.Errorf(\"calling to RevisionClient.MapCreateBulk with wrong type %T, need slice\", slice)}\n\t}\n\tbuilders := make([]*RevisionCreate, rv.Len())\n\tfor i := 0; i < rv.Len(); i++ {\n\t\tbuilders[i] = c.Create()\n\t\tsetFunc(builders[i], i)\n\t}\n\treturn &RevisionCreateBulk{config: c.config, builders: builders}\n}\n\n// Update returns an update builder for Revision.\nfunc (c *RevisionClient) Update() *RevisionUpdate {\n\tmutation := newRevisionMutation(c.config, OpUpdate)\n\treturn &RevisionUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}\n}\n\n// UpdateOne returns an update builder for the given entity.\nfunc (c *RevisionClient) UpdateOne(_m *Revision) *RevisionUpdateOne {\n\tmutation := newRevisionMutation(c.config, OpUpdateOne, withRevision(_m))\n\treturn &RevisionUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}\n}\n\n// UpdateOneID returns an update builder for the given id.\nfunc (c *RevisionClient) UpdateOneID(id string) *RevisionUpdateOne {\n\tmutation := newRevisionMutation(c.config, OpUpdateOne, withRevisionID(id))\n\treturn &RevisionUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}\n}\n\n// Delete returns a delete builder for Revision.\nfunc (c *RevisionClient) Delete() *RevisionDelete {\n\tmutation := newRevisionMutation(c.config, OpDelete)\n\treturn &RevisionDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}\n}\n\n// DeleteOne returns a builder for deleting the given entity.\nfunc (c *RevisionClient) DeleteOne(_m *Revision) *RevisionDeleteOne {\n\treturn c.DeleteOneID(_m.ID)\n}\n\n// DeleteOneID returns a builder for deleting the given entity by its id.\nfunc (c *RevisionClient) DeleteOneID(id string) *RevisionDeleteOne {\n\tbuilder := c.Delete().Where(revision.ID(id))\n\tbuilder.mutation.id = &id\n\tbuilder.mutation.op = OpDeleteOne\n\treturn &RevisionDeleteOne{builder}\n}\n\n// Query returns a query builder for Revision.\nfunc (c *RevisionClient) Query() *RevisionQuery {\n\treturn &RevisionQuery{\n\t\tconfig: c.config,\n\t\tctx:    &QueryContext{Type: TypeRevision},\n\t\tinters: c.Interceptors(),\n\t}\n}\n\n// Get returns a Revision entity by its id.\nfunc (c *RevisionClient) Get(ctx context.Context, id string) (*Revision, error) {\n\treturn c.Query().Where(revision.ID(id)).Only(ctx)\n}\n\n// GetX is like Get, but panics if an error occurs.\nfunc (c *RevisionClient) GetX(ctx context.Context, id string) *Revision {\n\tobj, err := c.Get(ctx, id)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn obj\n}\n\n// Hooks returns the client hooks.\nfunc (c *RevisionClient) Hooks() []Hook {\n\treturn c.hooks.Revision\n}\n\n// Interceptors returns the client interceptors.\nfunc (c *RevisionClient) Interceptors() []Interceptor {\n\treturn c.inters.Revision\n}\n\nfunc (c *RevisionClient) mutate(ctx context.Context, m *RevisionMutation) (Value, error) {\n\tswitch m.Op() {\n\tcase OpCreate:\n\t\treturn (&RevisionCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)\n\tcase OpUpdate:\n\t\treturn (&RevisionUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)\n\tcase OpUpdateOne:\n\t\treturn (&RevisionUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)\n\tcase OpDelete, OpDeleteOne:\n\t\treturn (&RevisionDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"ent: unknown Revision mutation op: %q\", m.Op())\n\t}\n}\n\n// hooks and interceptors per client, for fast access.\ntype (\n\thooks struct {\n\t\tRevision []ent.Hook\n\t}\n\tinters struct {\n\t\tRevision []ent.Interceptor\n\t}\n)\n\n// SchemaConfig represents alternative schema names for all tables\n// that can be passed at runtime.\ntype SchemaConfig = internal.SchemaConfig\n\n// AlternateSchemas allows alternate schema names to be\n// passed into ent operations.\nfunc AlternateSchema(schemaConfig SchemaConfig) Option {\n\treturn func(c *config) {\n\t\tc.schemaConfig = schemaConfig\n\t}\n}\n\n// ExecContext allows calling the underlying ExecContext method of the driver if it is supported by it.\n// See, database/sql#DB.ExecContext for more information.\nfunc (c *config) ExecContext(ctx context.Context, query string, args ...any) (stdsql.Result, error) {\n\tex, ok := c.driver.(interface {\n\t\tExecContext(context.Context, string, ...any) (stdsql.Result, error)\n\t})\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"Driver.ExecContext is not supported\")\n\t}\n\treturn ex.ExecContext(ctx, query, args...)\n}\n\n// QueryContext allows calling the underlying QueryContext method of the driver if it is supported by it.\n// See, database/sql#DB.QueryContext for more information.\nfunc (c *config) QueryContext(ctx context.Context, query string, args ...any) (*stdsql.Rows, error) {\n\tq, ok := c.driver.(interface {\n\t\tQueryContext(context.Context, string, ...any) (*stdsql.Rows, error)\n\t})\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"Driver.QueryContext is not supported\")\n\t}\n\treturn q.QueryContext(ctx, query, args...)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/convert.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport \"ariga.io/atlas/sql/migrate\"\n\n// SetRevision takes the values for each field from the given migrate.Revision.\nfunc (rc *RevisionCreate) SetRevision(rev *migrate.Revision) *RevisionCreate {\n\trc.SetID(rev.Version)\n\trc.SetDescription(rev.Description)\n\trc.SetType(rev.Type)\n\trc.SetApplied(rev.Applied)\n\trc.SetTotal(rev.Total)\n\trc.SetExecutedAt(rev.ExecutedAt)\n\trc.SetExecutionTime(rev.ExecutionTime)\n\trc.SetError(rev.Error)\n\trc.SetErrorStmt(rev.ErrorStmt)\n\trc.SetHash(rev.Hash)\n\trc.SetPartialHashes(rev.PartialHashes)\n\trc.SetOperatorVersion(rev.OperatorVersion)\n\treturn rc\n}\n\n// AtlasRevision returns an migrate.Revision from the current Revision.\nfunc (_m *Revision) AtlasRevision() *migrate.Revision {\n\treturn &migrate.Revision{\n\t\tVersion:         _m.ID,\n\t\tDescription:     _m.Description,\n\t\tType:            _m.Type,\n\t\tApplied:         _m.Applied,\n\t\tTotal:           _m.Total,\n\t\tExecutedAt:      _m.ExecutedAt,\n\t\tExecutionTime:   _m.ExecutionTime,\n\t\tError:           _m.Error,\n\t\tErrorStmt:       _m.ErrorStmt,\n\t\tHash:            _m.Hash,\n\t\tPartialHashes:   _m.PartialHashes,\n\t\tOperatorVersion: _m.OperatorVersion,\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/ent.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"sync\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"entgo.io/ent\"\n\t\"entgo.io/ent/dialect/sql\"\n\t\"entgo.io/ent/dialect/sql/sqlgraph\"\n)\n\n// ent aliases to avoid import conflicts in user's code.\ntype (\n\tOp            = ent.Op\n\tHook          = ent.Hook\n\tValue         = ent.Value\n\tQuery         = ent.Query\n\tQueryContext  = ent.QueryContext\n\tQuerier       = ent.Querier\n\tQuerierFunc   = ent.QuerierFunc\n\tInterceptor   = ent.Interceptor\n\tInterceptFunc = ent.InterceptFunc\n\tTraverser     = ent.Traverser\n\tTraverseFunc  = ent.TraverseFunc\n\tPolicy        = ent.Policy\n\tMutator       = ent.Mutator\n\tMutation      = ent.Mutation\n\tMutateFunc    = ent.MutateFunc\n)\n\ntype clientCtxKey struct{}\n\n// FromContext returns a Client stored inside a context, or nil if there isn't one.\nfunc FromContext(ctx context.Context) *Client {\n\tc, _ := ctx.Value(clientCtxKey{}).(*Client)\n\treturn c\n}\n\n// NewContext returns a new context with the given Client attached.\nfunc NewContext(parent context.Context, c *Client) context.Context {\n\treturn context.WithValue(parent, clientCtxKey{}, c)\n}\n\ntype txCtxKey struct{}\n\n// TxFromContext returns a Tx stored inside a context, or nil if there isn't one.\nfunc TxFromContext(ctx context.Context) *Tx {\n\ttx, _ := ctx.Value(txCtxKey{}).(*Tx)\n\treturn tx\n}\n\n// NewTxContext returns a new context with the given Tx attached.\nfunc NewTxContext(parent context.Context, tx *Tx) context.Context {\n\treturn context.WithValue(parent, txCtxKey{}, tx)\n}\n\n// OrderFunc applies an ordering on the sql selector.\n// Deprecated: Use Asc/Desc functions or the package builders instead.\ntype OrderFunc func(*sql.Selector)\n\nvar (\n\tinitCheck   sync.Once\n\tcolumnCheck sql.ColumnCheck\n)\n\n// checkColumn checks if the column exists in the given table.\nfunc checkColumn(t, c string) error {\n\tinitCheck.Do(func() {\n\t\tcolumnCheck = sql.NewColumnCheck(map[string]func(string) bool{\n\t\t\trevision.Table: revision.ValidColumn,\n\t\t})\n\t})\n\treturn columnCheck(t, c)\n}\n\n// Asc applies the given fields in ASC order.\nfunc Asc(fields ...string) func(*sql.Selector) {\n\treturn func(s *sql.Selector) {\n\t\tfor _, f := range fields {\n\t\t\tif err := checkColumn(s.TableName(), f); err != nil {\n\t\t\t\ts.AddError(&ValidationError{Name: f, err: fmt.Errorf(\"ent: %w\", err)})\n\t\t\t}\n\t\t\ts.OrderBy(sql.Asc(s.C(f)))\n\t\t}\n\t}\n}\n\n// Desc applies the given fields in DESC order.\nfunc Desc(fields ...string) func(*sql.Selector) {\n\treturn func(s *sql.Selector) {\n\t\tfor _, f := range fields {\n\t\t\tif err := checkColumn(s.TableName(), f); err != nil {\n\t\t\t\ts.AddError(&ValidationError{Name: f, err: fmt.Errorf(\"ent: %w\", err)})\n\t\t\t}\n\t\t\ts.OrderBy(sql.Desc(s.C(f)))\n\t\t}\n\t}\n}\n\n// AggregateFunc applies an aggregation step on the group-by traversal/selector.\ntype AggregateFunc func(*sql.Selector) string\n\n// As is a pseudo aggregation function for renaming another other functions with custom names. For example:\n//\n//\tGroupBy(field1, field2).\n//\tAggregate(ent.As(ent.Sum(field1), \"sum_field1\"), (ent.As(ent.Sum(field2), \"sum_field2\")).\n//\tScan(ctx, &v)\nfunc As(fn AggregateFunc, end string) AggregateFunc {\n\treturn func(s *sql.Selector) string {\n\t\treturn sql.As(fn(s), end)\n\t}\n}\n\n// Count applies the \"count\" aggregation function on each group.\nfunc Count() AggregateFunc {\n\treturn func(s *sql.Selector) string {\n\t\treturn sql.Count(\"*\")\n\t}\n}\n\n// Max applies the \"max\" aggregation function on the given field of each group.\nfunc Max(field string) AggregateFunc {\n\treturn func(s *sql.Selector) string {\n\t\tif err := checkColumn(s.TableName(), field); err != nil {\n\t\t\ts.AddError(&ValidationError{Name: field, err: fmt.Errorf(\"ent: %w\", err)})\n\t\t\treturn \"\"\n\t\t}\n\t\treturn sql.Max(s.C(field))\n\t}\n}\n\n// Mean applies the \"mean\" aggregation function on the given field of each group.\nfunc Mean(field string) AggregateFunc {\n\treturn func(s *sql.Selector) string {\n\t\tif err := checkColumn(s.TableName(), field); err != nil {\n\t\t\ts.AddError(&ValidationError{Name: field, err: fmt.Errorf(\"ent: %w\", err)})\n\t\t\treturn \"\"\n\t\t}\n\t\treturn sql.Avg(s.C(field))\n\t}\n}\n\n// Min applies the \"min\" aggregation function on the given field of each group.\nfunc Min(field string) AggregateFunc {\n\treturn func(s *sql.Selector) string {\n\t\tif err := checkColumn(s.TableName(), field); err != nil {\n\t\t\ts.AddError(&ValidationError{Name: field, err: fmt.Errorf(\"ent: %w\", err)})\n\t\t\treturn \"\"\n\t\t}\n\t\treturn sql.Min(s.C(field))\n\t}\n}\n\n// Sum applies the \"sum\" aggregation function on the given field of each group.\nfunc Sum(field string) AggregateFunc {\n\treturn func(s *sql.Selector) string {\n\t\tif err := checkColumn(s.TableName(), field); err != nil {\n\t\t\ts.AddError(&ValidationError{Name: field, err: fmt.Errorf(\"ent: %w\", err)})\n\t\t\treturn \"\"\n\t\t}\n\t\treturn sql.Sum(s.C(field))\n\t}\n}\n\n// ValidationError returns when validating a field or edge fails.\ntype ValidationError struct {\n\tName string // Field or edge name.\n\terr  error\n}\n\n// Error implements the error interface.\nfunc (e *ValidationError) Error() string {\n\treturn e.err.Error()\n}\n\n// Unwrap implements the errors.Wrapper interface.\nfunc (e *ValidationError) Unwrap() error {\n\treturn e.err\n}\n\n// IsValidationError returns a boolean indicating whether the error is a validation error.\nfunc IsValidationError(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tvar e *ValidationError\n\treturn errors.As(err, &e)\n}\n\n// NotFoundError returns when trying to fetch a specific entity and it was not found in the database.\ntype NotFoundError struct {\n\tlabel string\n}\n\n// Error implements the error interface.\nfunc (e *NotFoundError) Error() string {\n\treturn \"ent: \" + e.label + \" not found\"\n}\n\n// IsNotFound returns a boolean indicating whether the error is a not found error.\nfunc IsNotFound(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tvar e *NotFoundError\n\treturn errors.As(err, &e)\n}\n\n// MaskNotFound masks not found error.\nfunc MaskNotFound(err error) error {\n\tif IsNotFound(err) {\n\t\treturn nil\n\t}\n\treturn err\n}\n\n// NotSingularError returns when trying to fetch a singular entity and more then one was found in the database.\ntype NotSingularError struct {\n\tlabel string\n}\n\n// Error implements the error interface.\nfunc (e *NotSingularError) Error() string {\n\treturn \"ent: \" + e.label + \" not singular\"\n}\n\n// IsNotSingular returns a boolean indicating whether the error is a not singular error.\nfunc IsNotSingular(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tvar e *NotSingularError\n\treturn errors.As(err, &e)\n}\n\n// NotLoadedError returns when trying to get a node that was not loaded by the query.\ntype NotLoadedError struct {\n\tedge string\n}\n\n// Error implements the error interface.\nfunc (e *NotLoadedError) Error() string {\n\treturn \"ent: \" + e.edge + \" edge was not loaded\"\n}\n\n// IsNotLoaded returns a boolean indicating whether the error is a not loaded error.\nfunc IsNotLoaded(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tvar e *NotLoadedError\n\treturn errors.As(err, &e)\n}\n\n// ConstraintError returns when trying to create/update one or more entities and\n// one or more of their constraints failed. For example, violation of edge or\n// field uniqueness.\ntype ConstraintError struct {\n\tmsg  string\n\twrap error\n}\n\n// Error implements the error interface.\nfunc (e ConstraintError) Error() string {\n\treturn \"ent: constraint failed: \" + e.msg\n}\n\n// Unwrap implements the errors.Wrapper interface.\nfunc (e *ConstraintError) Unwrap() error {\n\treturn e.wrap\n}\n\n// IsConstraintError returns a boolean indicating whether the error is a constraint failure.\nfunc IsConstraintError(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tvar e *ConstraintError\n\treturn errors.As(err, &e)\n}\n\n// selector embedded by the different Select/GroupBy builders.\ntype selector struct {\n\tlabel string\n\tflds  *[]string\n\tfns   []AggregateFunc\n\tscan  func(context.Context, any) error\n}\n\n// ScanX is like Scan, but panics if an error occurs.\nfunc (s *selector) ScanX(ctx context.Context, v any) {\n\tif err := s.scan(ctx, v); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Strings returns list of strings from a selector. It is only allowed when selecting one field.\nfunc (s *selector) Strings(ctx context.Context) ([]string, error) {\n\tif len(*s.flds) > 1 {\n\t\treturn nil, errors.New(\"ent: Strings is not achievable when selecting more than 1 field\")\n\t}\n\tvar v []string\n\tif err := s.scan(ctx, &v); err != nil {\n\t\treturn nil, err\n\t}\n\treturn v, nil\n}\n\n// StringsX is like Strings, but panics if an error occurs.\nfunc (s *selector) StringsX(ctx context.Context) []string {\n\tv, err := s.Strings(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// String returns a single string from a selector. It is only allowed when selecting one field.\nfunc (s *selector) String(ctx context.Context) (_ string, err error) {\n\tvar v []string\n\tif v, err = s.Strings(ctx); err != nil {\n\t\treturn\n\t}\n\tswitch len(v) {\n\tcase 1:\n\t\treturn v[0], nil\n\tcase 0:\n\t\terr = &NotFoundError{s.label}\n\tdefault:\n\t\terr = fmt.Errorf(\"ent: Strings returned %d results when one was expected\", len(v))\n\t}\n\treturn\n}\n\n// StringX is like String, but panics if an error occurs.\nfunc (s *selector) StringX(ctx context.Context) string {\n\tv, err := s.String(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// Ints returns list of ints from a selector. It is only allowed when selecting one field.\nfunc (s *selector) Ints(ctx context.Context) ([]int, error) {\n\tif len(*s.flds) > 1 {\n\t\treturn nil, errors.New(\"ent: Ints is not achievable when selecting more than 1 field\")\n\t}\n\tvar v []int\n\tif err := s.scan(ctx, &v); err != nil {\n\t\treturn nil, err\n\t}\n\treturn v, nil\n}\n\n// IntsX is like Ints, but panics if an error occurs.\nfunc (s *selector) IntsX(ctx context.Context) []int {\n\tv, err := s.Ints(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// Int returns a single int from a selector. It is only allowed when selecting one field.\nfunc (s *selector) Int(ctx context.Context) (_ int, err error) {\n\tvar v []int\n\tif v, err = s.Ints(ctx); err != nil {\n\t\treturn\n\t}\n\tswitch len(v) {\n\tcase 1:\n\t\treturn v[0], nil\n\tcase 0:\n\t\terr = &NotFoundError{s.label}\n\tdefault:\n\t\terr = fmt.Errorf(\"ent: Ints returned %d results when one was expected\", len(v))\n\t}\n\treturn\n}\n\n// IntX is like Int, but panics if an error occurs.\nfunc (s *selector) IntX(ctx context.Context) int {\n\tv, err := s.Int(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// Float64s returns list of float64s from a selector. It is only allowed when selecting one field.\nfunc (s *selector) Float64s(ctx context.Context) ([]float64, error) {\n\tif len(*s.flds) > 1 {\n\t\treturn nil, errors.New(\"ent: Float64s is not achievable when selecting more than 1 field\")\n\t}\n\tvar v []float64\n\tif err := s.scan(ctx, &v); err != nil {\n\t\treturn nil, err\n\t}\n\treturn v, nil\n}\n\n// Float64sX is like Float64s, but panics if an error occurs.\nfunc (s *selector) Float64sX(ctx context.Context) []float64 {\n\tv, err := s.Float64s(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// Float64 returns a single float64 from a selector. It is only allowed when selecting one field.\nfunc (s *selector) Float64(ctx context.Context) (_ float64, err error) {\n\tvar v []float64\n\tif v, err = s.Float64s(ctx); err != nil {\n\t\treturn\n\t}\n\tswitch len(v) {\n\tcase 1:\n\t\treturn v[0], nil\n\tcase 0:\n\t\terr = &NotFoundError{s.label}\n\tdefault:\n\t\terr = fmt.Errorf(\"ent: Float64s returned %d results when one was expected\", len(v))\n\t}\n\treturn\n}\n\n// Float64X is like Float64, but panics if an error occurs.\nfunc (s *selector) Float64X(ctx context.Context) float64 {\n\tv, err := s.Float64(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// Bools returns list of bools from a selector. It is only allowed when selecting one field.\nfunc (s *selector) Bools(ctx context.Context) ([]bool, error) {\n\tif len(*s.flds) > 1 {\n\t\treturn nil, errors.New(\"ent: Bools is not achievable when selecting more than 1 field\")\n\t}\n\tvar v []bool\n\tif err := s.scan(ctx, &v); err != nil {\n\t\treturn nil, err\n\t}\n\treturn v, nil\n}\n\n// BoolsX is like Bools, but panics if an error occurs.\nfunc (s *selector) BoolsX(ctx context.Context) []bool {\n\tv, err := s.Bools(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// Bool returns a single bool from a selector. It is only allowed when selecting one field.\nfunc (s *selector) Bool(ctx context.Context) (_ bool, err error) {\n\tvar v []bool\n\tif v, err = s.Bools(ctx); err != nil {\n\t\treturn\n\t}\n\tswitch len(v) {\n\tcase 1:\n\t\treturn v[0], nil\n\tcase 0:\n\t\terr = &NotFoundError{s.label}\n\tdefault:\n\t\terr = fmt.Errorf(\"ent: Bools returned %d results when one was expected\", len(v))\n\t}\n\treturn\n}\n\n// BoolX is like Bool, but panics if an error occurs.\nfunc (s *selector) BoolX(ctx context.Context) bool {\n\tv, err := s.Bool(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// withHooks invokes the builder operation with the given hooks, if any.\nfunc withHooks[V Value, M any, PM interface {\n\t*M\n\tMutation\n}](ctx context.Context, exec func(context.Context) (V, error), mutation PM, hooks []Hook) (value V, err error) {\n\tif len(hooks) == 0 {\n\t\treturn exec(ctx)\n\t}\n\tvar mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {\n\t\tmutationT, ok := any(m).(PM)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"unexpected mutation type %T\", m)\n\t\t}\n\t\t// Set the mutation to the builder.\n\t\t*mutation = *mutationT\n\t\treturn exec(ctx)\n\t})\n\tfor i := len(hooks) - 1; i >= 0; i-- {\n\t\tif hooks[i] == nil {\n\t\t\treturn value, fmt.Errorf(\"ent: uninitialized hook (forgotten import ent/runtime?)\")\n\t\t}\n\t\tmut = hooks[i](mut)\n\t}\n\tv, err := mut.Mutate(ctx, mutation)\n\tif err != nil {\n\t\treturn value, err\n\t}\n\tnv, ok := v.(V)\n\tif !ok {\n\t\treturn value, fmt.Errorf(\"unexpected node type %T returned from %T\", v, mutation)\n\t}\n\treturn nv, nil\n}\n\n// setContextOp returns a new context with the given QueryContext attached (including its op) in case it does not exist.\nfunc setContextOp(ctx context.Context, qc *QueryContext, op string) context.Context {\n\tif ent.QueryFromContext(ctx) == nil {\n\t\tqc.Op = op\n\t\tctx = ent.NewQueryContext(ctx, qc)\n\t}\n\treturn ctx\n}\n\nfunc querierAll[V Value, Q interface {\n\tsqlAll(context.Context, ...queryHook) (V, error)\n}]() Querier {\n\treturn QuerierFunc(func(ctx context.Context, q Query) (Value, error) {\n\t\tquery, ok := q.(Q)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"unexpected query type %T\", q)\n\t\t}\n\t\treturn query.sqlAll(ctx)\n\t})\n}\n\nfunc querierCount[Q interface {\n\tsqlCount(context.Context) (int, error)\n}]() Querier {\n\treturn QuerierFunc(func(ctx context.Context, q Query) (Value, error) {\n\t\tquery, ok := q.(Q)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"unexpected query type %T\", q)\n\t\t}\n\t\treturn query.sqlCount(ctx)\n\t})\n}\n\nfunc withInterceptors[V Value](ctx context.Context, q Query, qr Querier, inters []Interceptor) (v V, err error) {\n\tfor i := len(inters) - 1; i >= 0; i-- {\n\t\tqr = inters[i].Intercept(qr)\n\t}\n\trv, err := qr.Query(ctx, q)\n\tif err != nil {\n\t\treturn v, err\n\t}\n\tvt, ok := rv.(V)\n\tif !ok {\n\t\treturn v, fmt.Errorf(\"unexpected type %T returned from %T. expected type: %T\", vt, q, v)\n\t}\n\treturn vt, nil\n}\n\nfunc scanWithInterceptors[Q1 ent.Query, Q2 interface {\n\tsqlScan(context.Context, Q1, any) error\n}](ctx context.Context, rootQuery Q1, selectOrGroup Q2, inters []Interceptor, v any) error {\n\trv := reflect.ValueOf(v)\n\tvar qr Querier = QuerierFunc(func(ctx context.Context, q Query) (Value, error) {\n\t\tquery, ok := q.(Q1)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"unexpected query type %T\", q)\n\t\t}\n\t\tif err := selectOrGroup.sqlScan(ctx, query, v); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif k := rv.Kind(); k == reflect.Pointer && rv.Elem().CanInterface() {\n\t\t\treturn rv.Elem().Interface(), nil\n\t\t}\n\t\treturn v, nil\n\t})\n\tfor i := len(inters) - 1; i >= 0; i-- {\n\t\tqr = inters[i].Intercept(qr)\n\t}\n\tvv, err := qr.Query(ctx, rootQuery)\n\tif err != nil {\n\t\treturn err\n\t}\n\tswitch rv2 := reflect.ValueOf(vv); {\n\tcase rv.IsNil(), rv2.IsNil(), rv.Kind() != reflect.Pointer:\n\tcase rv.Type() == rv2.Type():\n\t\trv.Elem().Set(rv2.Elem())\n\tcase rv.Elem().Type() == rv2.Type():\n\t\trv.Elem().Set(rv2)\n\t}\n\treturn nil\n}\n\n// queryHook describes an internal hook for the different sqlAll methods.\ntype queryHook func(context.Context, *sqlgraph.QuerySpec)\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/entc.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build ignore\n\npackage main\n\nimport (\n\t\"log\"\n\n\t\"entgo.io/ent/entc\"\n\t\"entgo.io/ent/entc/gen\"\n)\n\nfunc main() {\n\terr := entc.Generate(\"./schema\", &gen.Config{\n\t\tHeader: `// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n`,\n\t\tFeatures: []gen.Feature{\n\t\t\tgen.FeatureUpsert,\n\t\t\tgen.FeatureExecQuery,\n\t\t\tgen.FeatureSchemaConfig,\n\t\t},\n\t}, entc.TemplateDir(\"template\"))\n\tif err != nil {\n\t\tlog.Fatalf(\"running ent codegen: %v\", err)\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/enttest/enttest.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage enttest\n\nimport (\n\t\"context\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent\"\n\t// required by schema hooks.\n\t_ \"ariga.io/atlas/cmd/atlas/internal/migrate/ent/runtime\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/migrate\"\n\t\"entgo.io/ent/dialect/sql/schema\"\n)\n\ntype (\n\t// TestingT is the interface that is shared between\n\t// testing.T and testing.B and used by enttest.\n\tTestingT interface {\n\t\tFailNow()\n\t\tError(...any)\n\t}\n\n\t// Option configures client creation.\n\tOption func(*options)\n\n\toptions struct {\n\t\topts        []ent.Option\n\t\tmigrateOpts []schema.MigrateOption\n\t}\n)\n\n// WithOptions forwards options to client creation.\nfunc WithOptions(opts ...ent.Option) Option {\n\treturn func(o *options) {\n\t\to.opts = append(o.opts, opts...)\n\t}\n}\n\n// WithMigrateOptions forwards options to auto migration.\nfunc WithMigrateOptions(opts ...schema.MigrateOption) Option {\n\treturn func(o *options) {\n\t\to.migrateOpts = append(o.migrateOpts, opts...)\n\t}\n}\n\nfunc newOptions(opts []Option) *options {\n\to := &options{}\n\tfor _, opt := range opts {\n\t\topt(o)\n\t}\n\treturn o\n}\n\n// Open calls ent.Open and auto-run migration.\nfunc Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client {\n\to := newOptions(opts)\n\tc, err := ent.Open(driverName, dataSourceName, o.opts...)\n\tif err != nil {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n\tmigrateSchema(t, c, o)\n\treturn c\n}\n\n// NewClient calls ent.NewClient and auto-run migration.\nfunc NewClient(t TestingT, opts ...Option) *ent.Client {\n\to := newOptions(opts)\n\tc := ent.NewClient(o.opts...)\n\tmigrateSchema(t, c, o)\n\treturn c\n}\nfunc migrateSchema(t TestingT, c *ent.Client, o *options) {\n\ttables, err := schema.CopyTables(migrate.Tables)\n\tif err != nil {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n\tif err := migrate.Create(context.Background(), c.Schema, tables, o.migrateOpts...); err != nil {\n\t\tt.Error(err)\n\t\tt.FailNow()\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/generate.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage ent\n\n//go:generate go run -mod=mod entc.go\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/hook/hook.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage hook\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent\"\n)\n\n// The RevisionFunc type is an adapter to allow the use of ordinary\n// function as Revision mutator.\ntype RevisionFunc func(context.Context, *ent.RevisionMutation) (ent.Value, error)\n\n// Mutate calls f(ctx, m).\nfunc (f RevisionFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {\n\tif mv, ok := m.(*ent.RevisionMutation); ok {\n\t\treturn f(ctx, mv)\n\t}\n\treturn nil, fmt.Errorf(\"unexpected mutation type %T. expect *ent.RevisionMutation\", m)\n}\n\n// Condition is a hook condition function.\ntype Condition func(context.Context, ent.Mutation) bool\n\n// And groups conditions with the AND operator.\nfunc And(first, second Condition, rest ...Condition) Condition {\n\treturn func(ctx context.Context, m ent.Mutation) bool {\n\t\tif !first(ctx, m) || !second(ctx, m) {\n\t\t\treturn false\n\t\t}\n\t\tfor _, cond := range rest {\n\t\t\tif !cond(ctx, m) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n}\n\n// Or groups conditions with the OR operator.\nfunc Or(first, second Condition, rest ...Condition) Condition {\n\treturn func(ctx context.Context, m ent.Mutation) bool {\n\t\tif first(ctx, m) || second(ctx, m) {\n\t\t\treturn true\n\t\t}\n\t\tfor _, cond := range rest {\n\t\t\tif cond(ctx, m) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n}\n\n// Not negates a given condition.\nfunc Not(cond Condition) Condition {\n\treturn func(ctx context.Context, m ent.Mutation) bool {\n\t\treturn !cond(ctx, m)\n\t}\n}\n\n// HasOp is a condition testing mutation operation.\nfunc HasOp(op ent.Op) Condition {\n\treturn func(_ context.Context, m ent.Mutation) bool {\n\t\treturn m.Op().Is(op)\n\t}\n}\n\n// HasAddedFields is a condition validating `.AddedField` on fields.\nfunc HasAddedFields(field string, fields ...string) Condition {\n\treturn func(_ context.Context, m ent.Mutation) bool {\n\t\tif _, exists := m.AddedField(field); !exists {\n\t\t\treturn false\n\t\t}\n\t\tfor _, field := range fields {\n\t\t\tif _, exists := m.AddedField(field); !exists {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n}\n\n// HasClearedFields is a condition validating `.FieldCleared` on fields.\nfunc HasClearedFields(field string, fields ...string) Condition {\n\treturn func(_ context.Context, m ent.Mutation) bool {\n\t\tif exists := m.FieldCleared(field); !exists {\n\t\t\treturn false\n\t\t}\n\t\tfor _, field := range fields {\n\t\t\tif exists := m.FieldCleared(field); !exists {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n}\n\n// HasFields is a condition validating `.Field` on fields.\nfunc HasFields(field string, fields ...string) Condition {\n\treturn func(_ context.Context, m ent.Mutation) bool {\n\t\tif _, exists := m.Field(field); !exists {\n\t\t\treturn false\n\t\t}\n\t\tfor _, field := range fields {\n\t\t\tif _, exists := m.Field(field); !exists {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n}\n\n// If executes the given hook under condition.\n//\n//\thook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...)))\nfunc If(hk ent.Hook, cond Condition) ent.Hook {\n\treturn func(next ent.Mutator) ent.Mutator {\n\t\treturn ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) {\n\t\t\tif cond(ctx, m) {\n\t\t\t\treturn hk(next).Mutate(ctx, m)\n\t\t\t}\n\t\t\treturn next.Mutate(ctx, m)\n\t\t})\n\t}\n}\n\n// On executes the given hook only for the given operation.\n//\n//\thook.On(Log, ent.Delete|ent.Create)\nfunc On(hk ent.Hook, op ent.Op) ent.Hook {\n\treturn If(hk, HasOp(op))\n}\n\n// Unless skips the given hook only for the given operation.\n//\n//\thook.Unless(Log, ent.Update|ent.UpdateOne)\nfunc Unless(hk ent.Hook, op ent.Op) ent.Hook {\n\treturn If(hk, Not(HasOp(op)))\n}\n\n// FixedError is a hook returning a fixed error.\nfunc FixedError(err error) ent.Hook {\n\treturn func(ent.Mutator) ent.Mutator {\n\t\treturn ent.MutateFunc(func(context.Context, ent.Mutation) (ent.Value, error) {\n\t\t\treturn nil, err\n\t\t})\n\t}\n}\n\n// Reject returns a hook that rejects all operations that match op.\n//\n//\tfunc (T) Hooks() []ent.Hook {\n//\t\treturn []ent.Hook{\n//\t\t\tReject(ent.Delete|ent.Update),\n//\t\t}\n//\t}\nfunc Reject(op ent.Op) ent.Hook {\n\thk := FixedError(fmt.Errorf(\"%s operation is not allowed\", op))\n\treturn On(hk, op)\n}\n\n// Chain acts as a list of hooks and is effectively immutable.\n// Once created, it will always hold the same set of hooks in the same order.\ntype Chain struct {\n\thooks []ent.Hook\n}\n\n// NewChain creates a new chain of hooks.\nfunc NewChain(hooks ...ent.Hook) Chain {\n\treturn Chain{append([]ent.Hook(nil), hooks...)}\n}\n\n// Hook chains the list of hooks and returns the final hook.\nfunc (c Chain) Hook() ent.Hook {\n\treturn func(mutator ent.Mutator) ent.Mutator {\n\t\tfor i := len(c.hooks) - 1; i >= 0; i-- {\n\t\t\tmutator = c.hooks[i](mutator)\n\t\t}\n\t\treturn mutator\n\t}\n}\n\n// Append extends a chain, adding the specified hook\n// as the last ones in the mutation flow.\nfunc (c Chain) Append(hooks ...ent.Hook) Chain {\n\tnewHooks := make([]ent.Hook, 0, len(c.hooks)+len(hooks))\n\tnewHooks = append(newHooks, c.hooks...)\n\tnewHooks = append(newHooks, hooks...)\n\treturn Chain{newHooks}\n}\n\n// Extend extends a chain, adding the specified chain\n// as the last ones in the mutation flow.\nfunc (c Chain) Extend(chain Chain) Chain {\n\treturn c.Append(chain.hooks...)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/internal/schemaconfig.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage internal\n\nimport \"context\"\n\n// SchemaConfig represents alternative schema names for all tables\n// that can be passed at runtime.\ntype SchemaConfig struct {\n\tRevision string // Revision table.\n}\n\ntype schemaCtxKey struct{}\n\n// SchemaConfigFromContext returns a SchemaConfig stored inside a context, or empty if there isn't one.\nfunc SchemaConfigFromContext(ctx context.Context) SchemaConfig {\n\tconfig, _ := ctx.Value(schemaCtxKey{}).(SchemaConfig)\n\treturn config\n}\n\n// NewSchemaConfigContext returns a new context with the given SchemaConfig attached.\nfunc NewSchemaConfigContext(parent context.Context, config SchemaConfig) context.Context {\n\treturn context.WithValue(parent, schemaCtxKey{}, config)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/migrate/migrate.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage migrate\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"entgo.io/ent/dialect\"\n\t\"entgo.io/ent/dialect/sql/schema\"\n)\n\nvar (\n\t// WithGlobalUniqueID sets the universal ids options to the migration.\n\t// If this option is enabled, ent migration will allocate a 1<<32 range\n\t// for the ids of each entity (table).\n\t// Note that this option cannot be applied on tables that already exist.\n\tWithGlobalUniqueID = schema.WithGlobalUniqueID\n\t// WithDropColumn sets the drop column option to the migration.\n\t// If this option is enabled, ent migration will drop old columns\n\t// that were used for both fields and edges. This defaults to false.\n\tWithDropColumn = schema.WithDropColumn\n\t// WithDropIndex sets the drop index option to the migration.\n\t// If this option is enabled, ent migration will drop old indexes\n\t// that were defined in the schema. This defaults to false.\n\t// Note that unique constraints are defined using `UNIQUE INDEX`,\n\t// and therefore, it's recommended to enable this option to get more\n\t// flexibility in the schema changes.\n\tWithDropIndex = schema.WithDropIndex\n\t// WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true.\n\tWithForeignKeys = schema.WithForeignKeys\n)\n\n// Schema is the API for creating, migrating and dropping a schema.\ntype Schema struct {\n\tdrv dialect.Driver\n}\n\n// NewSchema creates a new schema client.\nfunc NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} }\n\n// Create creates all schema resources.\nfunc (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error {\n\treturn Create(ctx, s, Tables, opts...)\n}\n\n// Create creates all table resources using the given schema driver.\nfunc Create(ctx context.Context, s *Schema, tables []*schema.Table, opts ...schema.MigrateOption) error {\n\tmigrate, err := schema.NewMigrate(s.drv, opts...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"ent/migrate: %w\", err)\n\t}\n\treturn migrate.Create(ctx, tables...)\n}\n\n// WriteTo writes the schema changes to w instead of running them against the database.\n//\n//\tif err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil {\n//\t\tlog.Fatal(err)\n//\t}\nfunc (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error {\n\treturn Create(ctx, &Schema{drv: &schema.WriteDriver{Writer: w, Driver: s.drv}}, Tables, opts...)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/migrate/schema.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage migrate\n\nimport (\n\t\"entgo.io/ent/dialect/entsql\"\n\t\"entgo.io/ent/dialect/sql/schema\"\n\t\"entgo.io/ent/schema/field\"\n)\n\nvar (\n\t// AtlasSchemaRevisionsColumns holds the columns for the \"atlas_schema_revisions\" table.\n\tAtlasSchemaRevisionsColumns = []*schema.Column{\n\t\t{Name: \"version\", Type: field.TypeString},\n\t\t{Name: \"description\", Type: field.TypeString},\n\t\t{Name: \"type\", Type: field.TypeUint, Default: 2},\n\t\t{Name: \"applied\", Type: field.TypeInt, Default: 0},\n\t\t{Name: \"total\", Type: field.TypeInt, Default: 0},\n\t\t{Name: \"executed_at\", Type: field.TypeTime},\n\t\t{Name: \"execution_time\", Type: field.TypeInt64},\n\t\t{Name: \"error\", Type: field.TypeString, Nullable: true, Size: 2147483647},\n\t\t{Name: \"error_stmt\", Type: field.TypeString, Nullable: true, Size: 2147483647},\n\t\t{Name: \"hash\", Type: field.TypeString},\n\t\t{Name: \"partial_hashes\", Type: field.TypeJSON, Nullable: true},\n\t\t{Name: \"operator_version\", Type: field.TypeString},\n\t}\n\t// AtlasSchemaRevisionsTable holds the schema information for the \"atlas_schema_revisions\" table.\n\tAtlasSchemaRevisionsTable = &schema.Table{\n\t\tName:       \"atlas_schema_revisions\",\n\t\tColumns:    AtlasSchemaRevisionsColumns,\n\t\tPrimaryKey: []*schema.Column{AtlasSchemaRevisionsColumns[0]},\n\t}\n\t// Tables holds all the tables in the schema.\n\tTables = []*schema.Table{\n\t\tAtlasSchemaRevisionsTable,\n\t}\n)\n\nfunc init() {\n\tAtlasSchemaRevisionsTable.Annotation = &entsql.Annotation{\n\t\tTable: \"atlas_schema_revisions\",\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/mutation.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/predicate\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"entgo.io/ent\"\n\t\"entgo.io/ent/dialect/sql\"\n)\n\nconst (\n\t// Operation types.\n\tOpCreate    = ent.OpCreate\n\tOpDelete    = ent.OpDelete\n\tOpDeleteOne = ent.OpDeleteOne\n\tOpUpdate    = ent.OpUpdate\n\tOpUpdateOne = ent.OpUpdateOne\n\n\t// Node types.\n\tTypeRevision = \"Revision\"\n)\n\n// RevisionMutation represents an operation that mutates the Revision nodes in the graph.\ntype RevisionMutation struct {\n\tconfig\n\top                   Op\n\ttyp                  string\n\tid                   *string\n\tdescription          *string\n\t_type                *migrate.RevisionType\n\tadd_type             *migrate.RevisionType\n\tapplied              *int\n\taddapplied           *int\n\ttotal                *int\n\taddtotal             *int\n\texecuted_at          *time.Time\n\texecution_time       *time.Duration\n\taddexecution_time    *time.Duration\n\terror                *string\n\terror_stmt           *string\n\thash                 *string\n\tpartial_hashes       *[]string\n\tappendpartial_hashes []string\n\toperator_version     *string\n\tclearedFields        map[string]struct{}\n\tdone                 bool\n\toldValue             func(context.Context) (*Revision, error)\n\tpredicates           []predicate.Revision\n}\n\nvar _ ent.Mutation = (*RevisionMutation)(nil)\n\n// revisionOption allows management of the mutation configuration using functional options.\ntype revisionOption func(*RevisionMutation)\n\n// newRevisionMutation creates new mutation for the Revision entity.\nfunc newRevisionMutation(c config, op Op, opts ...revisionOption) *RevisionMutation {\n\tm := &RevisionMutation{\n\t\tconfig:        c,\n\t\top:            op,\n\t\ttyp:           TypeRevision,\n\t\tclearedFields: make(map[string]struct{}),\n\t}\n\tfor _, opt := range opts {\n\t\topt(m)\n\t}\n\treturn m\n}\n\n// withRevisionID sets the ID field of the mutation.\nfunc withRevisionID(id string) revisionOption {\n\treturn func(m *RevisionMutation) {\n\t\tvar (\n\t\t\terr   error\n\t\t\tonce  sync.Once\n\t\t\tvalue *Revision\n\t\t)\n\t\tm.oldValue = func(ctx context.Context) (*Revision, error) {\n\t\t\tonce.Do(func() {\n\t\t\t\tif m.done {\n\t\t\t\t\terr = errors.New(\"querying old values post mutation is not allowed\")\n\t\t\t\t} else {\n\t\t\t\t\tvalue, err = m.Client().Revision.Get(ctx, id)\n\t\t\t\t}\n\t\t\t})\n\t\t\treturn value, err\n\t\t}\n\t\tm.id = &id\n\t}\n}\n\n// withRevision sets the old Revision of the mutation.\nfunc withRevision(node *Revision) revisionOption {\n\treturn func(m *RevisionMutation) {\n\t\tm.oldValue = func(context.Context) (*Revision, error) {\n\t\t\treturn node, nil\n\t\t}\n\t\tm.id = &node.ID\n\t}\n}\n\n// Client returns a new `ent.Client` from the mutation. If the mutation was\n// executed in a transaction (ent.Tx), a transactional client is returned.\nfunc (m RevisionMutation) Client() *Client {\n\tclient := &Client{config: m.config}\n\tclient.init()\n\treturn client\n}\n\n// Tx returns an `ent.Tx` for mutations that were executed in transactions;\n// it returns an error otherwise.\nfunc (m RevisionMutation) Tx() (*Tx, error) {\n\tif _, ok := m.driver.(*txDriver); !ok {\n\t\treturn nil, errors.New(\"ent: mutation is not running in a transaction\")\n\t}\n\ttx := &Tx{config: m.config}\n\ttx.init()\n\treturn tx, nil\n}\n\n// SetID sets the value of the id field. Note that this\n// operation is only accepted on creation of Revision entities.\nfunc (m *RevisionMutation) SetID(id string) {\n\tm.id = &id\n}\n\n// ID returns the ID value in the mutation. Note that the ID is only available\n// if it was provided to the builder or after it was returned from the database.\nfunc (m *RevisionMutation) ID() (id string, exists bool) {\n\tif m.id == nil {\n\t\treturn\n\t}\n\treturn *m.id, true\n}\n\n// IDs queries the database and returns the entity ids that match the mutation's predicate.\n// That means, if the mutation is applied within a transaction with an isolation level such\n// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated\n// or updated by the mutation.\nfunc (m *RevisionMutation) IDs(ctx context.Context) ([]string, error) {\n\tswitch {\n\tcase m.op.Is(OpUpdateOne | OpDeleteOne):\n\t\tid, exists := m.ID()\n\t\tif exists {\n\t\t\treturn []string{id}, nil\n\t\t}\n\t\tfallthrough\n\tcase m.op.Is(OpUpdate | OpDelete):\n\t\treturn m.Client().Revision.Query().Where(m.predicates...).IDs(ctx)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"IDs is not allowed on %s operations\", m.op)\n\t}\n}\n\n// SetDescription sets the \"description\" field.\nfunc (m *RevisionMutation) SetDescription(s string) {\n\tm.description = &s\n}\n\n// Description returns the value of the \"description\" field in the mutation.\nfunc (m *RevisionMutation) Description() (r string, exists bool) {\n\tv := m.description\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldDescription returns the old \"description\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldDescription(ctx context.Context) (v string, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldDescription is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldDescription requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldDescription: %w\", err)\n\t}\n\treturn oldValue.Description, nil\n}\n\n// ResetDescription resets all changes to the \"description\" field.\nfunc (m *RevisionMutation) ResetDescription() {\n\tm.description = nil\n}\n\n// SetType sets the \"type\" field.\nfunc (m *RevisionMutation) SetType(mt migrate.RevisionType) {\n\tm._type = &mt\n\tm.add_type = nil\n}\n\n// GetType returns the value of the \"type\" field in the mutation.\nfunc (m *RevisionMutation) GetType() (r migrate.RevisionType, exists bool) {\n\tv := m._type\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldType returns the old \"type\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldType(ctx context.Context) (v migrate.RevisionType, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldType is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldType requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldType: %w\", err)\n\t}\n\treturn oldValue.Type, nil\n}\n\n// AddType adds mt to the \"type\" field.\nfunc (m *RevisionMutation) AddType(mt migrate.RevisionType) {\n\tif m.add_type != nil {\n\t\t*m.add_type += mt\n\t} else {\n\t\tm.add_type = &mt\n\t}\n}\n\n// AddedType returns the value that was added to the \"type\" field in this mutation.\nfunc (m *RevisionMutation) AddedType() (r migrate.RevisionType, exists bool) {\n\tv := m.add_type\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// ResetType resets all changes to the \"type\" field.\nfunc (m *RevisionMutation) ResetType() {\n\tm._type = nil\n\tm.add_type = nil\n}\n\n// SetApplied sets the \"applied\" field.\nfunc (m *RevisionMutation) SetApplied(i int) {\n\tm.applied = &i\n\tm.addapplied = nil\n}\n\n// Applied returns the value of the \"applied\" field in the mutation.\nfunc (m *RevisionMutation) Applied() (r int, exists bool) {\n\tv := m.applied\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldApplied returns the old \"applied\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldApplied(ctx context.Context) (v int, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldApplied is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldApplied requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldApplied: %w\", err)\n\t}\n\treturn oldValue.Applied, nil\n}\n\n// AddApplied adds i to the \"applied\" field.\nfunc (m *RevisionMutation) AddApplied(i int) {\n\tif m.addapplied != nil {\n\t\t*m.addapplied += i\n\t} else {\n\t\tm.addapplied = &i\n\t}\n}\n\n// AddedApplied returns the value that was added to the \"applied\" field in this mutation.\nfunc (m *RevisionMutation) AddedApplied() (r int, exists bool) {\n\tv := m.addapplied\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// ResetApplied resets all changes to the \"applied\" field.\nfunc (m *RevisionMutation) ResetApplied() {\n\tm.applied = nil\n\tm.addapplied = nil\n}\n\n// SetTotal sets the \"total\" field.\nfunc (m *RevisionMutation) SetTotal(i int) {\n\tm.total = &i\n\tm.addtotal = nil\n}\n\n// Total returns the value of the \"total\" field in the mutation.\nfunc (m *RevisionMutation) Total() (r int, exists bool) {\n\tv := m.total\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldTotal returns the old \"total\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldTotal(ctx context.Context) (v int, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldTotal is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldTotal requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldTotal: %w\", err)\n\t}\n\treturn oldValue.Total, nil\n}\n\n// AddTotal adds i to the \"total\" field.\nfunc (m *RevisionMutation) AddTotal(i int) {\n\tif m.addtotal != nil {\n\t\t*m.addtotal += i\n\t} else {\n\t\tm.addtotal = &i\n\t}\n}\n\n// AddedTotal returns the value that was added to the \"total\" field in this mutation.\nfunc (m *RevisionMutation) AddedTotal() (r int, exists bool) {\n\tv := m.addtotal\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// ResetTotal resets all changes to the \"total\" field.\nfunc (m *RevisionMutation) ResetTotal() {\n\tm.total = nil\n\tm.addtotal = nil\n}\n\n// SetExecutedAt sets the \"executed_at\" field.\nfunc (m *RevisionMutation) SetExecutedAt(t time.Time) {\n\tm.executed_at = &t\n}\n\n// ExecutedAt returns the value of the \"executed_at\" field in the mutation.\nfunc (m *RevisionMutation) ExecutedAt() (r time.Time, exists bool) {\n\tv := m.executed_at\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldExecutedAt returns the old \"executed_at\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldExecutedAt(ctx context.Context) (v time.Time, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldExecutedAt is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldExecutedAt requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldExecutedAt: %w\", err)\n\t}\n\treturn oldValue.ExecutedAt, nil\n}\n\n// ResetExecutedAt resets all changes to the \"executed_at\" field.\nfunc (m *RevisionMutation) ResetExecutedAt() {\n\tm.executed_at = nil\n}\n\n// SetExecutionTime sets the \"execution_time\" field.\nfunc (m *RevisionMutation) SetExecutionTime(t time.Duration) {\n\tm.execution_time = &t\n\tm.addexecution_time = nil\n}\n\n// ExecutionTime returns the value of the \"execution_time\" field in the mutation.\nfunc (m *RevisionMutation) ExecutionTime() (r time.Duration, exists bool) {\n\tv := m.execution_time\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldExecutionTime returns the old \"execution_time\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldExecutionTime(ctx context.Context) (v time.Duration, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldExecutionTime is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldExecutionTime requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldExecutionTime: %w\", err)\n\t}\n\treturn oldValue.ExecutionTime, nil\n}\n\n// AddExecutionTime adds t to the \"execution_time\" field.\nfunc (m *RevisionMutation) AddExecutionTime(t time.Duration) {\n\tif m.addexecution_time != nil {\n\t\t*m.addexecution_time += t\n\t} else {\n\t\tm.addexecution_time = &t\n\t}\n}\n\n// AddedExecutionTime returns the value that was added to the \"execution_time\" field in this mutation.\nfunc (m *RevisionMutation) AddedExecutionTime() (r time.Duration, exists bool) {\n\tv := m.addexecution_time\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// ResetExecutionTime resets all changes to the \"execution_time\" field.\nfunc (m *RevisionMutation) ResetExecutionTime() {\n\tm.execution_time = nil\n\tm.addexecution_time = nil\n}\n\n// SetError sets the \"error\" field.\nfunc (m *RevisionMutation) SetError(s string) {\n\tm.error = &s\n}\n\n// Error returns the value of the \"error\" field in the mutation.\nfunc (m *RevisionMutation) Error() (r string, exists bool) {\n\tv := m.error\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldError returns the old \"error\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldError(ctx context.Context) (v string, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldError is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldError requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldError: %w\", err)\n\t}\n\treturn oldValue.Error, nil\n}\n\n// ClearError clears the value of the \"error\" field.\nfunc (m *RevisionMutation) ClearError() {\n\tm.error = nil\n\tm.clearedFields[revision.FieldError] = struct{}{}\n}\n\n// ErrorCleared returns if the \"error\" field was cleared in this mutation.\nfunc (m *RevisionMutation) ErrorCleared() bool {\n\t_, ok := m.clearedFields[revision.FieldError]\n\treturn ok\n}\n\n// ResetError resets all changes to the \"error\" field.\nfunc (m *RevisionMutation) ResetError() {\n\tm.error = nil\n\tdelete(m.clearedFields, revision.FieldError)\n}\n\n// SetErrorStmt sets the \"error_stmt\" field.\nfunc (m *RevisionMutation) SetErrorStmt(s string) {\n\tm.error_stmt = &s\n}\n\n// ErrorStmt returns the value of the \"error_stmt\" field in the mutation.\nfunc (m *RevisionMutation) ErrorStmt() (r string, exists bool) {\n\tv := m.error_stmt\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldErrorStmt returns the old \"error_stmt\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldErrorStmt(ctx context.Context) (v string, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldErrorStmt is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldErrorStmt requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldErrorStmt: %w\", err)\n\t}\n\treturn oldValue.ErrorStmt, nil\n}\n\n// ClearErrorStmt clears the value of the \"error_stmt\" field.\nfunc (m *RevisionMutation) ClearErrorStmt() {\n\tm.error_stmt = nil\n\tm.clearedFields[revision.FieldErrorStmt] = struct{}{}\n}\n\n// ErrorStmtCleared returns if the \"error_stmt\" field was cleared in this mutation.\nfunc (m *RevisionMutation) ErrorStmtCleared() bool {\n\t_, ok := m.clearedFields[revision.FieldErrorStmt]\n\treturn ok\n}\n\n// ResetErrorStmt resets all changes to the \"error_stmt\" field.\nfunc (m *RevisionMutation) ResetErrorStmt() {\n\tm.error_stmt = nil\n\tdelete(m.clearedFields, revision.FieldErrorStmt)\n}\n\n// SetHash sets the \"hash\" field.\nfunc (m *RevisionMutation) SetHash(s string) {\n\tm.hash = &s\n}\n\n// Hash returns the value of the \"hash\" field in the mutation.\nfunc (m *RevisionMutation) Hash() (r string, exists bool) {\n\tv := m.hash\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldHash returns the old \"hash\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldHash(ctx context.Context) (v string, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldHash is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldHash requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldHash: %w\", err)\n\t}\n\treturn oldValue.Hash, nil\n}\n\n// ResetHash resets all changes to the \"hash\" field.\nfunc (m *RevisionMutation) ResetHash() {\n\tm.hash = nil\n}\n\n// SetPartialHashes sets the \"partial_hashes\" field.\nfunc (m *RevisionMutation) SetPartialHashes(s []string) {\n\tm.partial_hashes = &s\n\tm.appendpartial_hashes = nil\n}\n\n// PartialHashes returns the value of the \"partial_hashes\" field in the mutation.\nfunc (m *RevisionMutation) PartialHashes() (r []string, exists bool) {\n\tv := m.partial_hashes\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldPartialHashes returns the old \"partial_hashes\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldPartialHashes(ctx context.Context) (v []string, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldPartialHashes is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldPartialHashes requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldPartialHashes: %w\", err)\n\t}\n\treturn oldValue.PartialHashes, nil\n}\n\n// AppendPartialHashes adds s to the \"partial_hashes\" field.\nfunc (m *RevisionMutation) AppendPartialHashes(s []string) {\n\tm.appendpartial_hashes = append(m.appendpartial_hashes, s...)\n}\n\n// AppendedPartialHashes returns the list of values that were appended to the \"partial_hashes\" field in this mutation.\nfunc (m *RevisionMutation) AppendedPartialHashes() ([]string, bool) {\n\tif len(m.appendpartial_hashes) == 0 {\n\t\treturn nil, false\n\t}\n\treturn m.appendpartial_hashes, true\n}\n\n// ClearPartialHashes clears the value of the \"partial_hashes\" field.\nfunc (m *RevisionMutation) ClearPartialHashes() {\n\tm.partial_hashes = nil\n\tm.appendpartial_hashes = nil\n\tm.clearedFields[revision.FieldPartialHashes] = struct{}{}\n}\n\n// PartialHashesCleared returns if the \"partial_hashes\" field was cleared in this mutation.\nfunc (m *RevisionMutation) PartialHashesCleared() bool {\n\t_, ok := m.clearedFields[revision.FieldPartialHashes]\n\treturn ok\n}\n\n// ResetPartialHashes resets all changes to the \"partial_hashes\" field.\nfunc (m *RevisionMutation) ResetPartialHashes() {\n\tm.partial_hashes = nil\n\tm.appendpartial_hashes = nil\n\tdelete(m.clearedFields, revision.FieldPartialHashes)\n}\n\n// SetOperatorVersion sets the \"operator_version\" field.\nfunc (m *RevisionMutation) SetOperatorVersion(s string) {\n\tm.operator_version = &s\n}\n\n// OperatorVersion returns the value of the \"operator_version\" field in the mutation.\nfunc (m *RevisionMutation) OperatorVersion() (r string, exists bool) {\n\tv := m.operator_version\n\tif v == nil {\n\t\treturn\n\t}\n\treturn *v, true\n}\n\n// OldOperatorVersion returns the old \"operator_version\" field's value of the Revision entity.\n// If the Revision object wasn't provided to the builder, the object is fetched from the database.\n// An error is returned if the mutation operation is not UpdateOne, or the database query fails.\nfunc (m *RevisionMutation) OldOperatorVersion(ctx context.Context) (v string, err error) {\n\tif !m.op.Is(OpUpdateOne) {\n\t\treturn v, errors.New(\"OldOperatorVersion is only allowed on UpdateOne operations\")\n\t}\n\tif m.id == nil || m.oldValue == nil {\n\t\treturn v, errors.New(\"OldOperatorVersion requires an ID field in the mutation\")\n\t}\n\toldValue, err := m.oldValue(ctx)\n\tif err != nil {\n\t\treturn v, fmt.Errorf(\"querying old value for OldOperatorVersion: %w\", err)\n\t}\n\treturn oldValue.OperatorVersion, nil\n}\n\n// ResetOperatorVersion resets all changes to the \"operator_version\" field.\nfunc (m *RevisionMutation) ResetOperatorVersion() {\n\tm.operator_version = nil\n}\n\n// Where appends a list predicates to the RevisionMutation builder.\nfunc (m *RevisionMutation) Where(ps ...predicate.Revision) {\n\tm.predicates = append(m.predicates, ps...)\n}\n\n// WhereP appends storage-level predicates to the RevisionMutation builder. Using this method,\n// users can use type-assertion to append predicates that do not depend on any generated package.\nfunc (m *RevisionMutation) WhereP(ps ...func(*sql.Selector)) {\n\tp := make([]predicate.Revision, len(ps))\n\tfor i := range ps {\n\t\tp[i] = ps[i]\n\t}\n\tm.Where(p...)\n}\n\n// Op returns the operation name.\nfunc (m *RevisionMutation) Op() Op {\n\treturn m.op\n}\n\n// SetOp allows setting the mutation operation.\nfunc (m *RevisionMutation) SetOp(op Op) {\n\tm.op = op\n}\n\n// Type returns the node type of this mutation (Revision).\nfunc (m *RevisionMutation) Type() string {\n\treturn m.typ\n}\n\n// Fields returns all fields that were changed during this mutation. Note that in\n// order to get all numeric fields that were incremented/decremented, call\n// AddedFields().\nfunc (m *RevisionMutation) Fields() []string {\n\tfields := make([]string, 0, 11)\n\tif m.description != nil {\n\t\tfields = append(fields, revision.FieldDescription)\n\t}\n\tif m._type != nil {\n\t\tfields = append(fields, revision.FieldType)\n\t}\n\tif m.applied != nil {\n\t\tfields = append(fields, revision.FieldApplied)\n\t}\n\tif m.total != nil {\n\t\tfields = append(fields, revision.FieldTotal)\n\t}\n\tif m.executed_at != nil {\n\t\tfields = append(fields, revision.FieldExecutedAt)\n\t}\n\tif m.execution_time != nil {\n\t\tfields = append(fields, revision.FieldExecutionTime)\n\t}\n\tif m.error != nil {\n\t\tfields = append(fields, revision.FieldError)\n\t}\n\tif m.error_stmt != nil {\n\t\tfields = append(fields, revision.FieldErrorStmt)\n\t}\n\tif m.hash != nil {\n\t\tfields = append(fields, revision.FieldHash)\n\t}\n\tif m.partial_hashes != nil {\n\t\tfields = append(fields, revision.FieldPartialHashes)\n\t}\n\tif m.operator_version != nil {\n\t\tfields = append(fields, revision.FieldOperatorVersion)\n\t}\n\treturn fields\n}\n\n// Field returns the value of a field with the given name. The second boolean\n// return value indicates that this field was not set, or was not defined in the\n// schema.\nfunc (m *RevisionMutation) Field(name string) (ent.Value, bool) {\n\tswitch name {\n\tcase revision.FieldDescription:\n\t\treturn m.Description()\n\tcase revision.FieldType:\n\t\treturn m.GetType()\n\tcase revision.FieldApplied:\n\t\treturn m.Applied()\n\tcase revision.FieldTotal:\n\t\treturn m.Total()\n\tcase revision.FieldExecutedAt:\n\t\treturn m.ExecutedAt()\n\tcase revision.FieldExecutionTime:\n\t\treturn m.ExecutionTime()\n\tcase revision.FieldError:\n\t\treturn m.Error()\n\tcase revision.FieldErrorStmt:\n\t\treturn m.ErrorStmt()\n\tcase revision.FieldHash:\n\t\treturn m.Hash()\n\tcase revision.FieldPartialHashes:\n\t\treturn m.PartialHashes()\n\tcase revision.FieldOperatorVersion:\n\t\treturn m.OperatorVersion()\n\t}\n\treturn nil, false\n}\n\n// OldField returns the old value of the field from the database. An error is\n// returned if the mutation operation is not UpdateOne, or the query to the\n// database failed.\nfunc (m *RevisionMutation) OldField(ctx context.Context, name string) (ent.Value, error) {\n\tswitch name {\n\tcase revision.FieldDescription:\n\t\treturn m.OldDescription(ctx)\n\tcase revision.FieldType:\n\t\treturn m.OldType(ctx)\n\tcase revision.FieldApplied:\n\t\treturn m.OldApplied(ctx)\n\tcase revision.FieldTotal:\n\t\treturn m.OldTotal(ctx)\n\tcase revision.FieldExecutedAt:\n\t\treturn m.OldExecutedAt(ctx)\n\tcase revision.FieldExecutionTime:\n\t\treturn m.OldExecutionTime(ctx)\n\tcase revision.FieldError:\n\t\treturn m.OldError(ctx)\n\tcase revision.FieldErrorStmt:\n\t\treturn m.OldErrorStmt(ctx)\n\tcase revision.FieldHash:\n\t\treturn m.OldHash(ctx)\n\tcase revision.FieldPartialHashes:\n\t\treturn m.OldPartialHashes(ctx)\n\tcase revision.FieldOperatorVersion:\n\t\treturn m.OldOperatorVersion(ctx)\n\t}\n\treturn nil, fmt.Errorf(\"unknown Revision field %s\", name)\n}\n\n// SetField sets the value of a field with the given name. It returns an error if\n// the field is not defined in the schema, or if the type mismatched the field\n// type.\nfunc (m *RevisionMutation) SetField(name string, value ent.Value) error {\n\tswitch name {\n\tcase revision.FieldDescription:\n\t\tv, ok := value.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetDescription(v)\n\t\treturn nil\n\tcase revision.FieldType:\n\t\tv, ok := value.(migrate.RevisionType)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetType(v)\n\t\treturn nil\n\tcase revision.FieldApplied:\n\t\tv, ok := value.(int)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetApplied(v)\n\t\treturn nil\n\tcase revision.FieldTotal:\n\t\tv, ok := value.(int)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetTotal(v)\n\t\treturn nil\n\tcase revision.FieldExecutedAt:\n\t\tv, ok := value.(time.Time)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetExecutedAt(v)\n\t\treturn nil\n\tcase revision.FieldExecutionTime:\n\t\tv, ok := value.(time.Duration)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetExecutionTime(v)\n\t\treturn nil\n\tcase revision.FieldError:\n\t\tv, ok := value.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetError(v)\n\t\treturn nil\n\tcase revision.FieldErrorStmt:\n\t\tv, ok := value.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetErrorStmt(v)\n\t\treturn nil\n\tcase revision.FieldHash:\n\t\tv, ok := value.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetHash(v)\n\t\treturn nil\n\tcase revision.FieldPartialHashes:\n\t\tv, ok := value.([]string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetPartialHashes(v)\n\t\treturn nil\n\tcase revision.FieldOperatorVersion:\n\t\tv, ok := value.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.SetOperatorVersion(v)\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"unknown Revision field %s\", name)\n}\n\n// AddedFields returns all numeric fields that were incremented/decremented during\n// this mutation.\nfunc (m *RevisionMutation) AddedFields() []string {\n\tvar fields []string\n\tif m.add_type != nil {\n\t\tfields = append(fields, revision.FieldType)\n\t}\n\tif m.addapplied != nil {\n\t\tfields = append(fields, revision.FieldApplied)\n\t}\n\tif m.addtotal != nil {\n\t\tfields = append(fields, revision.FieldTotal)\n\t}\n\tif m.addexecution_time != nil {\n\t\tfields = append(fields, revision.FieldExecutionTime)\n\t}\n\treturn fields\n}\n\n// AddedField returns the numeric value that was incremented/decremented on a field\n// with the given name. The second boolean return value indicates that this field\n// was not set, or was not defined in the schema.\nfunc (m *RevisionMutation) AddedField(name string) (ent.Value, bool) {\n\tswitch name {\n\tcase revision.FieldType:\n\t\treturn m.AddedType()\n\tcase revision.FieldApplied:\n\t\treturn m.AddedApplied()\n\tcase revision.FieldTotal:\n\t\treturn m.AddedTotal()\n\tcase revision.FieldExecutionTime:\n\t\treturn m.AddedExecutionTime()\n\t}\n\treturn nil, false\n}\n\n// AddField adds the value to the field with the given name. It returns an error if\n// the field is not defined in the schema, or if the type mismatched the field\n// type.\nfunc (m *RevisionMutation) AddField(name string, value ent.Value) error {\n\tswitch name {\n\tcase revision.FieldType:\n\t\tv, ok := value.(migrate.RevisionType)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.AddType(v)\n\t\treturn nil\n\tcase revision.FieldApplied:\n\t\tv, ok := value.(int)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.AddApplied(v)\n\t\treturn nil\n\tcase revision.FieldTotal:\n\t\tv, ok := value.(int)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.AddTotal(v)\n\t\treturn nil\n\tcase revision.FieldExecutionTime:\n\t\tv, ok := value.(time.Duration)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected type %T for field %s\", value, name)\n\t\t}\n\t\tm.AddExecutionTime(v)\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"unknown Revision numeric field %s\", name)\n}\n\n// ClearedFields returns all nullable fields that were cleared during this\n// mutation.\nfunc (m *RevisionMutation) ClearedFields() []string {\n\tvar fields []string\n\tif m.FieldCleared(revision.FieldError) {\n\t\tfields = append(fields, revision.FieldError)\n\t}\n\tif m.FieldCleared(revision.FieldErrorStmt) {\n\t\tfields = append(fields, revision.FieldErrorStmt)\n\t}\n\tif m.FieldCleared(revision.FieldPartialHashes) {\n\t\tfields = append(fields, revision.FieldPartialHashes)\n\t}\n\treturn fields\n}\n\n// FieldCleared returns a boolean indicating if a field with the given name was\n// cleared in this mutation.\nfunc (m *RevisionMutation) FieldCleared(name string) bool {\n\t_, ok := m.clearedFields[name]\n\treturn ok\n}\n\n// ClearField clears the value of the field with the given name. It returns an\n// error if the field is not defined in the schema.\nfunc (m *RevisionMutation) ClearField(name string) error {\n\tswitch name {\n\tcase revision.FieldError:\n\t\tm.ClearError()\n\t\treturn nil\n\tcase revision.FieldErrorStmt:\n\t\tm.ClearErrorStmt()\n\t\treturn nil\n\tcase revision.FieldPartialHashes:\n\t\tm.ClearPartialHashes()\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"unknown Revision nullable field %s\", name)\n}\n\n// ResetField resets all changes in the mutation for the field with the given name.\n// It returns an error if the field is not defined in the schema.\nfunc (m *RevisionMutation) ResetField(name string) error {\n\tswitch name {\n\tcase revision.FieldDescription:\n\t\tm.ResetDescription()\n\t\treturn nil\n\tcase revision.FieldType:\n\t\tm.ResetType()\n\t\treturn nil\n\tcase revision.FieldApplied:\n\t\tm.ResetApplied()\n\t\treturn nil\n\tcase revision.FieldTotal:\n\t\tm.ResetTotal()\n\t\treturn nil\n\tcase revision.FieldExecutedAt:\n\t\tm.ResetExecutedAt()\n\t\treturn nil\n\tcase revision.FieldExecutionTime:\n\t\tm.ResetExecutionTime()\n\t\treturn nil\n\tcase revision.FieldError:\n\t\tm.ResetError()\n\t\treturn nil\n\tcase revision.FieldErrorStmt:\n\t\tm.ResetErrorStmt()\n\t\treturn nil\n\tcase revision.FieldHash:\n\t\tm.ResetHash()\n\t\treturn nil\n\tcase revision.FieldPartialHashes:\n\t\tm.ResetPartialHashes()\n\t\treturn nil\n\tcase revision.FieldOperatorVersion:\n\t\tm.ResetOperatorVersion()\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"unknown Revision field %s\", name)\n}\n\n// AddedEdges returns all edge names that were set/added in this mutation.\nfunc (m *RevisionMutation) AddedEdges() []string {\n\tedges := make([]string, 0, 0)\n\treturn edges\n}\n\n// AddedIDs returns all IDs (to other nodes) that were added for the given edge\n// name in this mutation.\nfunc (m *RevisionMutation) AddedIDs(name string) []ent.Value {\n\treturn nil\n}\n\n// RemovedEdges returns all edge names that were removed in this mutation.\nfunc (m *RevisionMutation) RemovedEdges() []string {\n\tedges := make([]string, 0, 0)\n\treturn edges\n}\n\n// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with\n// the given name in this mutation.\nfunc (m *RevisionMutation) RemovedIDs(name string) []ent.Value {\n\treturn nil\n}\n\n// ClearedEdges returns all edge names that were cleared in this mutation.\nfunc (m *RevisionMutation) ClearedEdges() []string {\n\tedges := make([]string, 0, 0)\n\treturn edges\n}\n\n// EdgeCleared returns a boolean which indicates if the edge with the given name\n// was cleared in this mutation.\nfunc (m *RevisionMutation) EdgeCleared(name string) bool {\n\treturn false\n}\n\n// ClearEdge clears the value of the edge with the given name. It returns an error\n// if that edge is not defined in the schema.\nfunc (m *RevisionMutation) ClearEdge(name string) error {\n\treturn fmt.Errorf(\"unknown Revision unique edge %s\", name)\n}\n\n// ResetEdge resets all changes to the edge with the given name in this mutation.\n// It returns an error if the edge is not defined in the schema.\nfunc (m *RevisionMutation) ResetEdge(name string) error {\n\treturn fmt.Errorf(\"unknown Revision edge %s\", name)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/predicate/predicate.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage predicate\n\nimport (\n\t\"entgo.io/ent/dialect/sql\"\n)\n\n// Revision is the predicate function for revision builders.\ntype Revision func(*sql.Selector)\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/revision/revision.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage revision\n\nimport (\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"entgo.io/ent/dialect/sql\"\n)\n\nconst (\n\t// Label holds the string label denoting the revision type in the database.\n\tLabel = \"revision\"\n\t// FieldID holds the string denoting the id field in the database.\n\tFieldID = \"version\"\n\t// FieldDescription holds the string denoting the description field in the database.\n\tFieldDescription = \"description\"\n\t// FieldType holds the string denoting the type field in the database.\n\tFieldType = \"type\"\n\t// FieldApplied holds the string denoting the applied field in the database.\n\tFieldApplied = \"applied\"\n\t// FieldTotal holds the string denoting the total field in the database.\n\tFieldTotal = \"total\"\n\t// FieldExecutedAt holds the string denoting the executed_at field in the database.\n\tFieldExecutedAt = \"executed_at\"\n\t// FieldExecutionTime holds the string denoting the execution_time field in the database.\n\tFieldExecutionTime = \"execution_time\"\n\t// FieldError holds the string denoting the error field in the database.\n\tFieldError = \"error\"\n\t// FieldErrorStmt holds the string denoting the error_stmt field in the database.\n\tFieldErrorStmt = \"error_stmt\"\n\t// FieldHash holds the string denoting the hash field in the database.\n\tFieldHash = \"hash\"\n\t// FieldPartialHashes holds the string denoting the partial_hashes field in the database.\n\tFieldPartialHashes = \"partial_hashes\"\n\t// FieldOperatorVersion holds the string denoting the operator_version field in the database.\n\tFieldOperatorVersion = \"operator_version\"\n\t// Table holds the table name of the revision in the database.\n\tTable = \"atlas_schema_revisions\"\n)\n\n// Columns holds all SQL columns for revision fields.\nvar Columns = []string{\n\tFieldID,\n\tFieldDescription,\n\tFieldType,\n\tFieldApplied,\n\tFieldTotal,\n\tFieldExecutedAt,\n\tFieldExecutionTime,\n\tFieldError,\n\tFieldErrorStmt,\n\tFieldHash,\n\tFieldPartialHashes,\n\tFieldOperatorVersion,\n}\n\n// ValidColumn reports if the column name is valid (part of the table columns).\nfunc ValidColumn(column string) bool {\n\tfor i := range Columns {\n\t\tif column == Columns[i] {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nvar (\n\t// DefaultType holds the default value on creation for the \"type\" field.\n\tDefaultType migrate.RevisionType\n\t// DefaultApplied holds the default value on creation for the \"applied\" field.\n\tDefaultApplied int\n\t// AppliedValidator is a validator for the \"applied\" field. It is called by the builders before save.\n\tAppliedValidator func(int) error\n\t// DefaultTotal holds the default value on creation for the \"total\" field.\n\tDefaultTotal int\n\t// TotalValidator is a validator for the \"total\" field. It is called by the builders before save.\n\tTotalValidator func(int) error\n)\n\n// OrderOption defines the ordering options for the Revision queries.\ntype OrderOption func(*sql.Selector)\n\n// ByID orders the results by the id field.\nfunc ByID(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldID, opts...).ToFunc()\n}\n\n// ByDescription orders the results by the description field.\nfunc ByDescription(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldDescription, opts...).ToFunc()\n}\n\n// ByType orders the results by the type field.\nfunc ByType(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldType, opts...).ToFunc()\n}\n\n// ByApplied orders the results by the applied field.\nfunc ByApplied(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldApplied, opts...).ToFunc()\n}\n\n// ByTotal orders the results by the total field.\nfunc ByTotal(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldTotal, opts...).ToFunc()\n}\n\n// ByExecutedAt orders the results by the executed_at field.\nfunc ByExecutedAt(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldExecutedAt, opts...).ToFunc()\n}\n\n// ByExecutionTime orders the results by the execution_time field.\nfunc ByExecutionTime(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldExecutionTime, opts...).ToFunc()\n}\n\n// ByError orders the results by the error field.\nfunc ByError(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldError, opts...).ToFunc()\n}\n\n// ByErrorStmt orders the results by the error_stmt field.\nfunc ByErrorStmt(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldErrorStmt, opts...).ToFunc()\n}\n\n// ByHash orders the results by the hash field.\nfunc ByHash(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldHash, opts...).ToFunc()\n}\n\n// ByOperatorVersion orders the results by the operator_version field.\nfunc ByOperatorVersion(opts ...sql.OrderTermOption) OrderOption {\n\treturn sql.OrderByField(FieldOperatorVersion, opts...).ToFunc()\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/revision/where.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage revision\n\nimport (\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/predicate\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"entgo.io/ent/dialect/sql\"\n)\n\n// ID filters vertices based on their ID field.\nfunc ID(id string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldID, id))\n}\n\n// IDEQ applies the EQ predicate on the ID field.\nfunc IDEQ(id string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldID, id))\n}\n\n// IDNEQ applies the NEQ predicate on the ID field.\nfunc IDNEQ(id string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNEQ(FieldID, id))\n}\n\n// IDIn applies the In predicate on the ID field.\nfunc IDIn(ids ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldIn(FieldID, ids...))\n}\n\n// IDNotIn applies the NotIn predicate on the ID field.\nfunc IDNotIn(ids ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotIn(FieldID, ids...))\n}\n\n// IDGT applies the GT predicate on the ID field.\nfunc IDGT(id string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGT(FieldID, id))\n}\n\n// IDGTE applies the GTE predicate on the ID field.\nfunc IDGTE(id string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGTE(FieldID, id))\n}\n\n// IDLT applies the LT predicate on the ID field.\nfunc IDLT(id string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLT(FieldID, id))\n}\n\n// IDLTE applies the LTE predicate on the ID field.\nfunc IDLTE(id string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLTE(FieldID, id))\n}\n\n// IDEqualFold applies the EqualFold predicate on the ID field.\nfunc IDEqualFold(id string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEqualFold(FieldID, id))\n}\n\n// IDContainsFold applies the ContainsFold predicate on the ID field.\nfunc IDContainsFold(id string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContainsFold(FieldID, id))\n}\n\n// Description applies equality check predicate on the \"description\" field. It's identical to DescriptionEQ.\nfunc Description(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldDescription, v))\n}\n\n// Type applies equality check predicate on the \"type\" field. It's identical to TypeEQ.\nfunc Type(v migrate.RevisionType) predicate.Revision {\n\tvc := uint(v)\n\treturn predicate.Revision(sql.FieldEQ(FieldType, vc))\n}\n\n// Applied applies equality check predicate on the \"applied\" field. It's identical to AppliedEQ.\nfunc Applied(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldApplied, v))\n}\n\n// Total applies equality check predicate on the \"total\" field. It's identical to TotalEQ.\nfunc Total(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldTotal, v))\n}\n\n// ExecutedAt applies equality check predicate on the \"executed_at\" field. It's identical to ExecutedAtEQ.\nfunc ExecutedAt(v time.Time) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldExecutedAt, v))\n}\n\n// ExecutionTime applies equality check predicate on the \"execution_time\" field. It's identical to ExecutionTimeEQ.\nfunc ExecutionTime(v time.Duration) predicate.Revision {\n\tvc := int64(v)\n\treturn predicate.Revision(sql.FieldEQ(FieldExecutionTime, vc))\n}\n\n// Error applies equality check predicate on the \"error\" field. It's identical to ErrorEQ.\nfunc Error(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldError, v))\n}\n\n// ErrorStmt applies equality check predicate on the \"error_stmt\" field. It's identical to ErrorStmtEQ.\nfunc ErrorStmt(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldErrorStmt, v))\n}\n\n// Hash applies equality check predicate on the \"hash\" field. It's identical to HashEQ.\nfunc Hash(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldHash, v))\n}\n\n// OperatorVersion applies equality check predicate on the \"operator_version\" field. It's identical to OperatorVersionEQ.\nfunc OperatorVersion(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldOperatorVersion, v))\n}\n\n// DescriptionEQ applies the EQ predicate on the \"description\" field.\nfunc DescriptionEQ(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldDescription, v))\n}\n\n// DescriptionNEQ applies the NEQ predicate on the \"description\" field.\nfunc DescriptionNEQ(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNEQ(FieldDescription, v))\n}\n\n// DescriptionIn applies the In predicate on the \"description\" field.\nfunc DescriptionIn(vs ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldIn(FieldDescription, vs...))\n}\n\n// DescriptionNotIn applies the NotIn predicate on the \"description\" field.\nfunc DescriptionNotIn(vs ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotIn(FieldDescription, vs...))\n}\n\n// DescriptionGT applies the GT predicate on the \"description\" field.\nfunc DescriptionGT(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGT(FieldDescription, v))\n}\n\n// DescriptionGTE applies the GTE predicate on the \"description\" field.\nfunc DescriptionGTE(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGTE(FieldDescription, v))\n}\n\n// DescriptionLT applies the LT predicate on the \"description\" field.\nfunc DescriptionLT(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLT(FieldDescription, v))\n}\n\n// DescriptionLTE applies the LTE predicate on the \"description\" field.\nfunc DescriptionLTE(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLTE(FieldDescription, v))\n}\n\n// DescriptionContains applies the Contains predicate on the \"description\" field.\nfunc DescriptionContains(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContains(FieldDescription, v))\n}\n\n// DescriptionHasPrefix applies the HasPrefix predicate on the \"description\" field.\nfunc DescriptionHasPrefix(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldHasPrefix(FieldDescription, v))\n}\n\n// DescriptionHasSuffix applies the HasSuffix predicate on the \"description\" field.\nfunc DescriptionHasSuffix(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldHasSuffix(FieldDescription, v))\n}\n\n// DescriptionEqualFold applies the EqualFold predicate on the \"description\" field.\nfunc DescriptionEqualFold(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEqualFold(FieldDescription, v))\n}\n\n// DescriptionContainsFold applies the ContainsFold predicate on the \"description\" field.\nfunc DescriptionContainsFold(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContainsFold(FieldDescription, v))\n}\n\n// TypeEQ applies the EQ predicate on the \"type\" field.\nfunc TypeEQ(v migrate.RevisionType) predicate.Revision {\n\tvc := uint(v)\n\treturn predicate.Revision(sql.FieldEQ(FieldType, vc))\n}\n\n// TypeNEQ applies the NEQ predicate on the \"type\" field.\nfunc TypeNEQ(v migrate.RevisionType) predicate.Revision {\n\tvc := uint(v)\n\treturn predicate.Revision(sql.FieldNEQ(FieldType, vc))\n}\n\n// TypeIn applies the In predicate on the \"type\" field.\nfunc TypeIn(vs ...migrate.RevisionType) predicate.Revision {\n\tv := make([]any, len(vs))\n\tfor i := range v {\n\t\tv[i] = uint(vs[i])\n\t}\n\treturn predicate.Revision(sql.FieldIn(FieldType, v...))\n}\n\n// TypeNotIn applies the NotIn predicate on the \"type\" field.\nfunc TypeNotIn(vs ...migrate.RevisionType) predicate.Revision {\n\tv := make([]any, len(vs))\n\tfor i := range v {\n\t\tv[i] = uint(vs[i])\n\t}\n\treturn predicate.Revision(sql.FieldNotIn(FieldType, v...))\n}\n\n// TypeGT applies the GT predicate on the \"type\" field.\nfunc TypeGT(v migrate.RevisionType) predicate.Revision {\n\tvc := uint(v)\n\treturn predicate.Revision(sql.FieldGT(FieldType, vc))\n}\n\n// TypeGTE applies the GTE predicate on the \"type\" field.\nfunc TypeGTE(v migrate.RevisionType) predicate.Revision {\n\tvc := uint(v)\n\treturn predicate.Revision(sql.FieldGTE(FieldType, vc))\n}\n\n// TypeLT applies the LT predicate on the \"type\" field.\nfunc TypeLT(v migrate.RevisionType) predicate.Revision {\n\tvc := uint(v)\n\treturn predicate.Revision(sql.FieldLT(FieldType, vc))\n}\n\n// TypeLTE applies the LTE predicate on the \"type\" field.\nfunc TypeLTE(v migrate.RevisionType) predicate.Revision {\n\tvc := uint(v)\n\treturn predicate.Revision(sql.FieldLTE(FieldType, vc))\n}\n\n// AppliedEQ applies the EQ predicate on the \"applied\" field.\nfunc AppliedEQ(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldApplied, v))\n}\n\n// AppliedNEQ applies the NEQ predicate on the \"applied\" field.\nfunc AppliedNEQ(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNEQ(FieldApplied, v))\n}\n\n// AppliedIn applies the In predicate on the \"applied\" field.\nfunc AppliedIn(vs ...int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldIn(FieldApplied, vs...))\n}\n\n// AppliedNotIn applies the NotIn predicate on the \"applied\" field.\nfunc AppliedNotIn(vs ...int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotIn(FieldApplied, vs...))\n}\n\n// AppliedGT applies the GT predicate on the \"applied\" field.\nfunc AppliedGT(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGT(FieldApplied, v))\n}\n\n// AppliedGTE applies the GTE predicate on the \"applied\" field.\nfunc AppliedGTE(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGTE(FieldApplied, v))\n}\n\n// AppliedLT applies the LT predicate on the \"applied\" field.\nfunc AppliedLT(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLT(FieldApplied, v))\n}\n\n// AppliedLTE applies the LTE predicate on the \"applied\" field.\nfunc AppliedLTE(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLTE(FieldApplied, v))\n}\n\n// TotalEQ applies the EQ predicate on the \"total\" field.\nfunc TotalEQ(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldTotal, v))\n}\n\n// TotalNEQ applies the NEQ predicate on the \"total\" field.\nfunc TotalNEQ(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNEQ(FieldTotal, v))\n}\n\n// TotalIn applies the In predicate on the \"total\" field.\nfunc TotalIn(vs ...int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldIn(FieldTotal, vs...))\n}\n\n// TotalNotIn applies the NotIn predicate on the \"total\" field.\nfunc TotalNotIn(vs ...int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotIn(FieldTotal, vs...))\n}\n\n// TotalGT applies the GT predicate on the \"total\" field.\nfunc TotalGT(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGT(FieldTotal, v))\n}\n\n// TotalGTE applies the GTE predicate on the \"total\" field.\nfunc TotalGTE(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGTE(FieldTotal, v))\n}\n\n// TotalLT applies the LT predicate on the \"total\" field.\nfunc TotalLT(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLT(FieldTotal, v))\n}\n\n// TotalLTE applies the LTE predicate on the \"total\" field.\nfunc TotalLTE(v int) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLTE(FieldTotal, v))\n}\n\n// ExecutedAtEQ applies the EQ predicate on the \"executed_at\" field.\nfunc ExecutedAtEQ(v time.Time) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldExecutedAt, v))\n}\n\n// ExecutedAtNEQ applies the NEQ predicate on the \"executed_at\" field.\nfunc ExecutedAtNEQ(v time.Time) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNEQ(FieldExecutedAt, v))\n}\n\n// ExecutedAtIn applies the In predicate on the \"executed_at\" field.\nfunc ExecutedAtIn(vs ...time.Time) predicate.Revision {\n\treturn predicate.Revision(sql.FieldIn(FieldExecutedAt, vs...))\n}\n\n// ExecutedAtNotIn applies the NotIn predicate on the \"executed_at\" field.\nfunc ExecutedAtNotIn(vs ...time.Time) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotIn(FieldExecutedAt, vs...))\n}\n\n// ExecutedAtGT applies the GT predicate on the \"executed_at\" field.\nfunc ExecutedAtGT(v time.Time) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGT(FieldExecutedAt, v))\n}\n\n// ExecutedAtGTE applies the GTE predicate on the \"executed_at\" field.\nfunc ExecutedAtGTE(v time.Time) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGTE(FieldExecutedAt, v))\n}\n\n// ExecutedAtLT applies the LT predicate on the \"executed_at\" field.\nfunc ExecutedAtLT(v time.Time) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLT(FieldExecutedAt, v))\n}\n\n// ExecutedAtLTE applies the LTE predicate on the \"executed_at\" field.\nfunc ExecutedAtLTE(v time.Time) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLTE(FieldExecutedAt, v))\n}\n\n// ExecutionTimeEQ applies the EQ predicate on the \"execution_time\" field.\nfunc ExecutionTimeEQ(v time.Duration) predicate.Revision {\n\tvc := int64(v)\n\treturn predicate.Revision(sql.FieldEQ(FieldExecutionTime, vc))\n}\n\n// ExecutionTimeNEQ applies the NEQ predicate on the \"execution_time\" field.\nfunc ExecutionTimeNEQ(v time.Duration) predicate.Revision {\n\tvc := int64(v)\n\treturn predicate.Revision(sql.FieldNEQ(FieldExecutionTime, vc))\n}\n\n// ExecutionTimeIn applies the In predicate on the \"execution_time\" field.\nfunc ExecutionTimeIn(vs ...time.Duration) predicate.Revision {\n\tv := make([]any, len(vs))\n\tfor i := range v {\n\t\tv[i] = int64(vs[i])\n\t}\n\treturn predicate.Revision(sql.FieldIn(FieldExecutionTime, v...))\n}\n\n// ExecutionTimeNotIn applies the NotIn predicate on the \"execution_time\" field.\nfunc ExecutionTimeNotIn(vs ...time.Duration) predicate.Revision {\n\tv := make([]any, len(vs))\n\tfor i := range v {\n\t\tv[i] = int64(vs[i])\n\t}\n\treturn predicate.Revision(sql.FieldNotIn(FieldExecutionTime, v...))\n}\n\n// ExecutionTimeGT applies the GT predicate on the \"execution_time\" field.\nfunc ExecutionTimeGT(v time.Duration) predicate.Revision {\n\tvc := int64(v)\n\treturn predicate.Revision(sql.FieldGT(FieldExecutionTime, vc))\n}\n\n// ExecutionTimeGTE applies the GTE predicate on the \"execution_time\" field.\nfunc ExecutionTimeGTE(v time.Duration) predicate.Revision {\n\tvc := int64(v)\n\treturn predicate.Revision(sql.FieldGTE(FieldExecutionTime, vc))\n}\n\n// ExecutionTimeLT applies the LT predicate on the \"execution_time\" field.\nfunc ExecutionTimeLT(v time.Duration) predicate.Revision {\n\tvc := int64(v)\n\treturn predicate.Revision(sql.FieldLT(FieldExecutionTime, vc))\n}\n\n// ExecutionTimeLTE applies the LTE predicate on the \"execution_time\" field.\nfunc ExecutionTimeLTE(v time.Duration) predicate.Revision {\n\tvc := int64(v)\n\treturn predicate.Revision(sql.FieldLTE(FieldExecutionTime, vc))\n}\n\n// ErrorEQ applies the EQ predicate on the \"error\" field.\nfunc ErrorEQ(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldError, v))\n}\n\n// ErrorNEQ applies the NEQ predicate on the \"error\" field.\nfunc ErrorNEQ(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNEQ(FieldError, v))\n}\n\n// ErrorIn applies the In predicate on the \"error\" field.\nfunc ErrorIn(vs ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldIn(FieldError, vs...))\n}\n\n// ErrorNotIn applies the NotIn predicate on the \"error\" field.\nfunc ErrorNotIn(vs ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotIn(FieldError, vs...))\n}\n\n// ErrorGT applies the GT predicate on the \"error\" field.\nfunc ErrorGT(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGT(FieldError, v))\n}\n\n// ErrorGTE applies the GTE predicate on the \"error\" field.\nfunc ErrorGTE(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGTE(FieldError, v))\n}\n\n// ErrorLT applies the LT predicate on the \"error\" field.\nfunc ErrorLT(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLT(FieldError, v))\n}\n\n// ErrorLTE applies the LTE predicate on the \"error\" field.\nfunc ErrorLTE(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLTE(FieldError, v))\n}\n\n// ErrorContains applies the Contains predicate on the \"error\" field.\nfunc ErrorContains(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContains(FieldError, v))\n}\n\n// ErrorHasPrefix applies the HasPrefix predicate on the \"error\" field.\nfunc ErrorHasPrefix(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldHasPrefix(FieldError, v))\n}\n\n// ErrorHasSuffix applies the HasSuffix predicate on the \"error\" field.\nfunc ErrorHasSuffix(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldHasSuffix(FieldError, v))\n}\n\n// ErrorIsNil applies the IsNil predicate on the \"error\" field.\nfunc ErrorIsNil() predicate.Revision {\n\treturn predicate.Revision(sql.FieldIsNull(FieldError))\n}\n\n// ErrorNotNil applies the NotNil predicate on the \"error\" field.\nfunc ErrorNotNil() predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotNull(FieldError))\n}\n\n// ErrorEqualFold applies the EqualFold predicate on the \"error\" field.\nfunc ErrorEqualFold(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEqualFold(FieldError, v))\n}\n\n// ErrorContainsFold applies the ContainsFold predicate on the \"error\" field.\nfunc ErrorContainsFold(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContainsFold(FieldError, v))\n}\n\n// ErrorStmtEQ applies the EQ predicate on the \"error_stmt\" field.\nfunc ErrorStmtEQ(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldErrorStmt, v))\n}\n\n// ErrorStmtNEQ applies the NEQ predicate on the \"error_stmt\" field.\nfunc ErrorStmtNEQ(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNEQ(FieldErrorStmt, v))\n}\n\n// ErrorStmtIn applies the In predicate on the \"error_stmt\" field.\nfunc ErrorStmtIn(vs ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldIn(FieldErrorStmt, vs...))\n}\n\n// ErrorStmtNotIn applies the NotIn predicate on the \"error_stmt\" field.\nfunc ErrorStmtNotIn(vs ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotIn(FieldErrorStmt, vs...))\n}\n\n// ErrorStmtGT applies the GT predicate on the \"error_stmt\" field.\nfunc ErrorStmtGT(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGT(FieldErrorStmt, v))\n}\n\n// ErrorStmtGTE applies the GTE predicate on the \"error_stmt\" field.\nfunc ErrorStmtGTE(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGTE(FieldErrorStmt, v))\n}\n\n// ErrorStmtLT applies the LT predicate on the \"error_stmt\" field.\nfunc ErrorStmtLT(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLT(FieldErrorStmt, v))\n}\n\n// ErrorStmtLTE applies the LTE predicate on the \"error_stmt\" field.\nfunc ErrorStmtLTE(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLTE(FieldErrorStmt, v))\n}\n\n// ErrorStmtContains applies the Contains predicate on the \"error_stmt\" field.\nfunc ErrorStmtContains(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContains(FieldErrorStmt, v))\n}\n\n// ErrorStmtHasPrefix applies the HasPrefix predicate on the \"error_stmt\" field.\nfunc ErrorStmtHasPrefix(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldHasPrefix(FieldErrorStmt, v))\n}\n\n// ErrorStmtHasSuffix applies the HasSuffix predicate on the \"error_stmt\" field.\nfunc ErrorStmtHasSuffix(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldHasSuffix(FieldErrorStmt, v))\n}\n\n// ErrorStmtIsNil applies the IsNil predicate on the \"error_stmt\" field.\nfunc ErrorStmtIsNil() predicate.Revision {\n\treturn predicate.Revision(sql.FieldIsNull(FieldErrorStmt))\n}\n\n// ErrorStmtNotNil applies the NotNil predicate on the \"error_stmt\" field.\nfunc ErrorStmtNotNil() predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotNull(FieldErrorStmt))\n}\n\n// ErrorStmtEqualFold applies the EqualFold predicate on the \"error_stmt\" field.\nfunc ErrorStmtEqualFold(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEqualFold(FieldErrorStmt, v))\n}\n\n// ErrorStmtContainsFold applies the ContainsFold predicate on the \"error_stmt\" field.\nfunc ErrorStmtContainsFold(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContainsFold(FieldErrorStmt, v))\n}\n\n// HashEQ applies the EQ predicate on the \"hash\" field.\nfunc HashEQ(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldHash, v))\n}\n\n// HashNEQ applies the NEQ predicate on the \"hash\" field.\nfunc HashNEQ(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNEQ(FieldHash, v))\n}\n\n// HashIn applies the In predicate on the \"hash\" field.\nfunc HashIn(vs ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldIn(FieldHash, vs...))\n}\n\n// HashNotIn applies the NotIn predicate on the \"hash\" field.\nfunc HashNotIn(vs ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotIn(FieldHash, vs...))\n}\n\n// HashGT applies the GT predicate on the \"hash\" field.\nfunc HashGT(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGT(FieldHash, v))\n}\n\n// HashGTE applies the GTE predicate on the \"hash\" field.\nfunc HashGTE(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGTE(FieldHash, v))\n}\n\n// HashLT applies the LT predicate on the \"hash\" field.\nfunc HashLT(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLT(FieldHash, v))\n}\n\n// HashLTE applies the LTE predicate on the \"hash\" field.\nfunc HashLTE(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLTE(FieldHash, v))\n}\n\n// HashContains applies the Contains predicate on the \"hash\" field.\nfunc HashContains(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContains(FieldHash, v))\n}\n\n// HashHasPrefix applies the HasPrefix predicate on the \"hash\" field.\nfunc HashHasPrefix(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldHasPrefix(FieldHash, v))\n}\n\n// HashHasSuffix applies the HasSuffix predicate on the \"hash\" field.\nfunc HashHasSuffix(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldHasSuffix(FieldHash, v))\n}\n\n// HashEqualFold applies the EqualFold predicate on the \"hash\" field.\nfunc HashEqualFold(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEqualFold(FieldHash, v))\n}\n\n// HashContainsFold applies the ContainsFold predicate on the \"hash\" field.\nfunc HashContainsFold(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContainsFold(FieldHash, v))\n}\n\n// PartialHashesIsNil applies the IsNil predicate on the \"partial_hashes\" field.\nfunc PartialHashesIsNil() predicate.Revision {\n\treturn predicate.Revision(sql.FieldIsNull(FieldPartialHashes))\n}\n\n// PartialHashesNotNil applies the NotNil predicate on the \"partial_hashes\" field.\nfunc PartialHashesNotNil() predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotNull(FieldPartialHashes))\n}\n\n// OperatorVersionEQ applies the EQ predicate on the \"operator_version\" field.\nfunc OperatorVersionEQ(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEQ(FieldOperatorVersion, v))\n}\n\n// OperatorVersionNEQ applies the NEQ predicate on the \"operator_version\" field.\nfunc OperatorVersionNEQ(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNEQ(FieldOperatorVersion, v))\n}\n\n// OperatorVersionIn applies the In predicate on the \"operator_version\" field.\nfunc OperatorVersionIn(vs ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldIn(FieldOperatorVersion, vs...))\n}\n\n// OperatorVersionNotIn applies the NotIn predicate on the \"operator_version\" field.\nfunc OperatorVersionNotIn(vs ...string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldNotIn(FieldOperatorVersion, vs...))\n}\n\n// OperatorVersionGT applies the GT predicate on the \"operator_version\" field.\nfunc OperatorVersionGT(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGT(FieldOperatorVersion, v))\n}\n\n// OperatorVersionGTE applies the GTE predicate on the \"operator_version\" field.\nfunc OperatorVersionGTE(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldGTE(FieldOperatorVersion, v))\n}\n\n// OperatorVersionLT applies the LT predicate on the \"operator_version\" field.\nfunc OperatorVersionLT(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLT(FieldOperatorVersion, v))\n}\n\n// OperatorVersionLTE applies the LTE predicate on the \"operator_version\" field.\nfunc OperatorVersionLTE(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldLTE(FieldOperatorVersion, v))\n}\n\n// OperatorVersionContains applies the Contains predicate on the \"operator_version\" field.\nfunc OperatorVersionContains(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContains(FieldOperatorVersion, v))\n}\n\n// OperatorVersionHasPrefix applies the HasPrefix predicate on the \"operator_version\" field.\nfunc OperatorVersionHasPrefix(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldHasPrefix(FieldOperatorVersion, v))\n}\n\n// OperatorVersionHasSuffix applies the HasSuffix predicate on the \"operator_version\" field.\nfunc OperatorVersionHasSuffix(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldHasSuffix(FieldOperatorVersion, v))\n}\n\n// OperatorVersionEqualFold applies the EqualFold predicate on the \"operator_version\" field.\nfunc OperatorVersionEqualFold(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldEqualFold(FieldOperatorVersion, v))\n}\n\n// OperatorVersionContainsFold applies the ContainsFold predicate on the \"operator_version\" field.\nfunc OperatorVersionContainsFold(v string) predicate.Revision {\n\treturn predicate.Revision(sql.FieldContainsFold(FieldOperatorVersion, v))\n}\n\n// And groups predicates with the AND operator between them.\nfunc And(predicates ...predicate.Revision) predicate.Revision {\n\treturn predicate.Revision(sql.AndPredicates(predicates...))\n}\n\n// Or groups predicates with the OR operator between them.\nfunc Or(predicates ...predicate.Revision) predicate.Revision {\n\treturn predicate.Revision(sql.OrPredicates(predicates...))\n}\n\n// Not applies the not operator on the given predicate.\nfunc Not(p predicate.Revision) predicate.Revision {\n\treturn predicate.Revision(sql.NotPredicates(p))\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/revision.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"entgo.io/ent\"\n\t\"entgo.io/ent/dialect/sql\"\n)\n\n// Revision is the model entity for the Revision schema.\ntype Revision struct {\n\tconfig `json:\"-\"`\n\t// ID of the ent.\n\tID string `json:\"id,omitempty\"`\n\t// Description holds the value of the \"description\" field.\n\tDescription string `json:\"description,omitempty\"`\n\t// Type holds the value of the \"type\" field.\n\tType migrate.RevisionType `json:\"type,omitempty\"`\n\t// Applied holds the value of the \"applied\" field.\n\tApplied int `json:\"applied,omitempty\"`\n\t// Total holds the value of the \"total\" field.\n\tTotal int `json:\"total,omitempty\"`\n\t// ExecutedAt holds the value of the \"executed_at\" field.\n\tExecutedAt time.Time `json:\"executed_at,omitempty\"`\n\t// ExecutionTime holds the value of the \"execution_time\" field.\n\tExecutionTime time.Duration `json:\"execution_time,omitempty\"`\n\t// Error holds the value of the \"error\" field.\n\tError string `json:\"error,omitempty\"`\n\t// ErrorStmt holds the value of the \"error_stmt\" field.\n\tErrorStmt string `json:\"error_stmt,omitempty\"`\n\t// Hash holds the value of the \"hash\" field.\n\tHash string `json:\"hash,omitempty\"`\n\t// PartialHashes holds the value of the \"partial_hashes\" field.\n\tPartialHashes []string `json:\"partial_hashes,omitempty\"`\n\t// OperatorVersion holds the value of the \"operator_version\" field.\n\tOperatorVersion string `json:\"operator_version,omitempty\"`\n\tselectValues    sql.SelectValues\n}\n\n// scanValues returns the types for scanning values from sql.Rows.\nfunc (*Revision) scanValues(columns []string) ([]any, error) {\n\tvalues := make([]any, len(columns))\n\tfor i := range columns {\n\t\tswitch columns[i] {\n\t\tcase revision.FieldPartialHashes:\n\t\t\tvalues[i] = new([]byte)\n\t\tcase revision.FieldType, revision.FieldApplied, revision.FieldTotal, revision.FieldExecutionTime:\n\t\t\tvalues[i] = new(sql.NullInt64)\n\t\tcase revision.FieldID, revision.FieldDescription, revision.FieldError, revision.FieldErrorStmt, revision.FieldHash, revision.FieldOperatorVersion:\n\t\t\tvalues[i] = new(sql.NullString)\n\t\tcase revision.FieldExecutedAt:\n\t\t\tvalues[i] = new(sql.NullTime)\n\t\tdefault:\n\t\t\tvalues[i] = new(sql.UnknownType)\n\t\t}\n\t}\n\treturn values, nil\n}\n\n// assignValues assigns the values that were returned from sql.Rows (after scanning)\n// to the Revision fields.\nfunc (_m *Revision) assignValues(columns []string, values []any) error {\n\tif m, n := len(values), len(columns); m < n {\n\t\treturn fmt.Errorf(\"mismatch number of scan values: %d != %d\", m, n)\n\t}\n\tfor i := range columns {\n\t\tswitch columns[i] {\n\t\tcase revision.FieldID:\n\t\t\tif value, ok := values[i].(*sql.NullString); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field id\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.ID = value.String\n\t\t\t}\n\t\tcase revision.FieldDescription:\n\t\t\tif value, ok := values[i].(*sql.NullString); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field description\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.Description = value.String\n\t\t\t}\n\t\tcase revision.FieldType:\n\t\t\tif value, ok := values[i].(*sql.NullInt64); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field type\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.Type = migrate.RevisionType(value.Int64)\n\t\t\t}\n\t\tcase revision.FieldApplied:\n\t\t\tif value, ok := values[i].(*sql.NullInt64); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field applied\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.Applied = int(value.Int64)\n\t\t\t}\n\t\tcase revision.FieldTotal:\n\t\t\tif value, ok := values[i].(*sql.NullInt64); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field total\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.Total = int(value.Int64)\n\t\t\t}\n\t\tcase revision.FieldExecutedAt:\n\t\t\tif value, ok := values[i].(*sql.NullTime); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field executed_at\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.ExecutedAt = value.Time\n\t\t\t}\n\t\tcase revision.FieldExecutionTime:\n\t\t\tif value, ok := values[i].(*sql.NullInt64); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field execution_time\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.ExecutionTime = time.Duration(value.Int64)\n\t\t\t}\n\t\tcase revision.FieldError:\n\t\t\tif value, ok := values[i].(*sql.NullString); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field error\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.Error = value.String\n\t\t\t}\n\t\tcase revision.FieldErrorStmt:\n\t\t\tif value, ok := values[i].(*sql.NullString); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field error_stmt\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.ErrorStmt = value.String\n\t\t\t}\n\t\tcase revision.FieldHash:\n\t\t\tif value, ok := values[i].(*sql.NullString); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field hash\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.Hash = value.String\n\t\t\t}\n\t\tcase revision.FieldPartialHashes:\n\t\t\tif value, ok := values[i].(*[]byte); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field partial_hashes\", values[i])\n\t\t\t} else if value != nil && len(*value) > 0 {\n\t\t\t\tif err := json.Unmarshal(*value, &_m.PartialHashes); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"unmarshal field partial_hashes: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\tcase revision.FieldOperatorVersion:\n\t\t\tif value, ok := values[i].(*sql.NullString); !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected type %T for field operator_version\", values[i])\n\t\t\t} else if value.Valid {\n\t\t\t\t_m.OperatorVersion = value.String\n\t\t\t}\n\t\tdefault:\n\t\t\t_m.selectValues.Set(columns[i], values[i])\n\t\t}\n\t}\n\treturn nil\n}\n\n// Value returns the ent.Value that was dynamically selected and assigned to the Revision.\n// This includes values selected through modifiers, order, etc.\nfunc (_m *Revision) Value(name string) (ent.Value, error) {\n\treturn _m.selectValues.Get(name)\n}\n\n// Update returns a builder for updating this Revision.\n// Note that you need to call Revision.Unwrap() before calling this method if this Revision\n// was returned from a transaction, and the transaction was committed or rolled back.\nfunc (_m *Revision) Update() *RevisionUpdateOne {\n\treturn NewRevisionClient(_m.config).UpdateOne(_m)\n}\n\n// Unwrap unwraps the Revision entity that was returned from a transaction after it was closed,\n// so that all future queries will be executed through the driver which created the transaction.\nfunc (_m *Revision) Unwrap() *Revision {\n\t_tx, ok := _m.config.driver.(*txDriver)\n\tif !ok {\n\t\tpanic(\"ent: Revision is not a transactional entity\")\n\t}\n\t_m.config.driver = _tx.drv\n\treturn _m\n}\n\n// String implements the fmt.Stringer.\nfunc (_m *Revision) String() string {\n\tvar builder strings.Builder\n\tbuilder.WriteString(\"Revision(\")\n\tbuilder.WriteString(fmt.Sprintf(\"id=%v, \", _m.ID))\n\tbuilder.WriteString(\"description=\")\n\tbuilder.WriteString(_m.Description)\n\tbuilder.WriteString(\", \")\n\tbuilder.WriteString(\"type=\")\n\tbuilder.WriteString(fmt.Sprintf(\"%v\", _m.Type))\n\tbuilder.WriteString(\", \")\n\tbuilder.WriteString(\"applied=\")\n\tbuilder.WriteString(fmt.Sprintf(\"%v\", _m.Applied))\n\tbuilder.WriteString(\", \")\n\tbuilder.WriteString(\"total=\")\n\tbuilder.WriteString(fmt.Sprintf(\"%v\", _m.Total))\n\tbuilder.WriteString(\", \")\n\tbuilder.WriteString(\"executed_at=\")\n\tbuilder.WriteString(_m.ExecutedAt.Format(time.ANSIC))\n\tbuilder.WriteString(\", \")\n\tbuilder.WriteString(\"execution_time=\")\n\tbuilder.WriteString(fmt.Sprintf(\"%v\", _m.ExecutionTime))\n\tbuilder.WriteString(\", \")\n\tbuilder.WriteString(\"error=\")\n\tbuilder.WriteString(_m.Error)\n\tbuilder.WriteString(\", \")\n\tbuilder.WriteString(\"error_stmt=\")\n\tbuilder.WriteString(_m.ErrorStmt)\n\tbuilder.WriteString(\", \")\n\tbuilder.WriteString(\"hash=\")\n\tbuilder.WriteString(_m.Hash)\n\tbuilder.WriteString(\", \")\n\tbuilder.WriteString(\"partial_hashes=\")\n\tbuilder.WriteString(fmt.Sprintf(\"%v\", _m.PartialHashes))\n\tbuilder.WriteString(\", \")\n\tbuilder.WriteString(\"operator_version=\")\n\tbuilder.WriteString(_m.OperatorVersion)\n\tbuilder.WriteByte(')')\n\treturn builder.String()\n}\n\n// Revisions is a parsable slice of Revision.\ntype Revisions []*Revision\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/revision_create.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"entgo.io/ent/dialect\"\n\t\"entgo.io/ent/dialect/sql\"\n\t\"entgo.io/ent/dialect/sql/sqlgraph\"\n\t\"entgo.io/ent/schema/field\"\n)\n\n// RevisionCreate is the builder for creating a Revision entity.\ntype RevisionCreate struct {\n\tconfig\n\tmutation *RevisionMutation\n\thooks    []Hook\n\tconflict []sql.ConflictOption\n}\n\n// SetDescription sets the \"description\" field.\nfunc (_c *RevisionCreate) SetDescription(v string) *RevisionCreate {\n\t_c.mutation.SetDescription(v)\n\treturn _c\n}\n\n// SetType sets the \"type\" field.\nfunc (_c *RevisionCreate) SetType(v migrate.RevisionType) *RevisionCreate {\n\t_c.mutation.SetType(v)\n\treturn _c\n}\n\n// SetNillableType sets the \"type\" field if the given value is not nil.\nfunc (_c *RevisionCreate) SetNillableType(v *migrate.RevisionType) *RevisionCreate {\n\tif v != nil {\n\t\t_c.SetType(*v)\n\t}\n\treturn _c\n}\n\n// SetApplied sets the \"applied\" field.\nfunc (_c *RevisionCreate) SetApplied(v int) *RevisionCreate {\n\t_c.mutation.SetApplied(v)\n\treturn _c\n}\n\n// SetNillableApplied sets the \"applied\" field if the given value is not nil.\nfunc (_c *RevisionCreate) SetNillableApplied(v *int) *RevisionCreate {\n\tif v != nil {\n\t\t_c.SetApplied(*v)\n\t}\n\treturn _c\n}\n\n// SetTotal sets the \"total\" field.\nfunc (_c *RevisionCreate) SetTotal(v int) *RevisionCreate {\n\t_c.mutation.SetTotal(v)\n\treturn _c\n}\n\n// SetNillableTotal sets the \"total\" field if the given value is not nil.\nfunc (_c *RevisionCreate) SetNillableTotal(v *int) *RevisionCreate {\n\tif v != nil {\n\t\t_c.SetTotal(*v)\n\t}\n\treturn _c\n}\n\n// SetExecutedAt sets the \"executed_at\" field.\nfunc (_c *RevisionCreate) SetExecutedAt(v time.Time) *RevisionCreate {\n\t_c.mutation.SetExecutedAt(v)\n\treturn _c\n}\n\n// SetExecutionTime sets the \"execution_time\" field.\nfunc (_c *RevisionCreate) SetExecutionTime(v time.Duration) *RevisionCreate {\n\t_c.mutation.SetExecutionTime(v)\n\treturn _c\n}\n\n// SetError sets the \"error\" field.\nfunc (_c *RevisionCreate) SetError(v string) *RevisionCreate {\n\t_c.mutation.SetError(v)\n\treturn _c\n}\n\n// SetNillableError sets the \"error\" field if the given value is not nil.\nfunc (_c *RevisionCreate) SetNillableError(v *string) *RevisionCreate {\n\tif v != nil {\n\t\t_c.SetError(*v)\n\t}\n\treturn _c\n}\n\n// SetErrorStmt sets the \"error_stmt\" field.\nfunc (_c *RevisionCreate) SetErrorStmt(v string) *RevisionCreate {\n\t_c.mutation.SetErrorStmt(v)\n\treturn _c\n}\n\n// SetNillableErrorStmt sets the \"error_stmt\" field if the given value is not nil.\nfunc (_c *RevisionCreate) SetNillableErrorStmt(v *string) *RevisionCreate {\n\tif v != nil {\n\t\t_c.SetErrorStmt(*v)\n\t}\n\treturn _c\n}\n\n// SetHash sets the \"hash\" field.\nfunc (_c *RevisionCreate) SetHash(v string) *RevisionCreate {\n\t_c.mutation.SetHash(v)\n\treturn _c\n}\n\n// SetPartialHashes sets the \"partial_hashes\" field.\nfunc (_c *RevisionCreate) SetPartialHashes(v []string) *RevisionCreate {\n\t_c.mutation.SetPartialHashes(v)\n\treturn _c\n}\n\n// SetOperatorVersion sets the \"operator_version\" field.\nfunc (_c *RevisionCreate) SetOperatorVersion(v string) *RevisionCreate {\n\t_c.mutation.SetOperatorVersion(v)\n\treturn _c\n}\n\n// SetID sets the \"id\" field.\nfunc (_c *RevisionCreate) SetID(v string) *RevisionCreate {\n\t_c.mutation.SetID(v)\n\treturn _c\n}\n\n// Mutation returns the RevisionMutation object of the builder.\nfunc (_c *RevisionCreate) Mutation() *RevisionMutation {\n\treturn _c.mutation\n}\n\n// Save creates the Revision in the database.\nfunc (_c *RevisionCreate) Save(ctx context.Context) (*Revision, error) {\n\t_c.defaults()\n\treturn withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks)\n}\n\n// SaveX calls Save and panics if Save returns an error.\nfunc (_c *RevisionCreate) SaveX(ctx context.Context) *Revision {\n\tv, err := _c.Save(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// Exec executes the query.\nfunc (_c *RevisionCreate) Exec(ctx context.Context) error {\n\t_, err := _c.Save(ctx)\n\treturn err\n}\n\n// ExecX is like Exec, but panics if an error occurs.\nfunc (_c *RevisionCreate) ExecX(ctx context.Context) {\n\tif err := _c.Exec(ctx); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// defaults sets the default values of the builder before save.\nfunc (_c *RevisionCreate) defaults() {\n\tif _, ok := _c.mutation.GetType(); !ok {\n\t\tv := revision.DefaultType\n\t\t_c.mutation.SetType(v)\n\t}\n\tif _, ok := _c.mutation.Applied(); !ok {\n\t\tv := revision.DefaultApplied\n\t\t_c.mutation.SetApplied(v)\n\t}\n\tif _, ok := _c.mutation.Total(); !ok {\n\t\tv := revision.DefaultTotal\n\t\t_c.mutation.SetTotal(v)\n\t}\n}\n\n// check runs all checks and user-defined validators on the builder.\nfunc (_c *RevisionCreate) check() error {\n\tif _, ok := _c.mutation.Description(); !ok {\n\t\treturn &ValidationError{Name: \"description\", err: errors.New(`ent: missing required field \"Revision.description\"`)}\n\t}\n\tif _, ok := _c.mutation.GetType(); !ok {\n\t\treturn &ValidationError{Name: \"type\", err: errors.New(`ent: missing required field \"Revision.type\"`)}\n\t}\n\tif _, ok := _c.mutation.Applied(); !ok {\n\t\treturn &ValidationError{Name: \"applied\", err: errors.New(`ent: missing required field \"Revision.applied\"`)}\n\t}\n\tif v, ok := _c.mutation.Applied(); ok {\n\t\tif err := revision.AppliedValidator(v); err != nil {\n\t\t\treturn &ValidationError{Name: \"applied\", err: fmt.Errorf(`ent: validator failed for field \"Revision.applied\": %w`, err)}\n\t\t}\n\t}\n\tif _, ok := _c.mutation.Total(); !ok {\n\t\treturn &ValidationError{Name: \"total\", err: errors.New(`ent: missing required field \"Revision.total\"`)}\n\t}\n\tif v, ok := _c.mutation.Total(); ok {\n\t\tif err := revision.TotalValidator(v); err != nil {\n\t\t\treturn &ValidationError{Name: \"total\", err: fmt.Errorf(`ent: validator failed for field \"Revision.total\": %w`, err)}\n\t\t}\n\t}\n\tif _, ok := _c.mutation.ExecutedAt(); !ok {\n\t\treturn &ValidationError{Name: \"executed_at\", err: errors.New(`ent: missing required field \"Revision.executed_at\"`)}\n\t}\n\tif _, ok := _c.mutation.ExecutionTime(); !ok {\n\t\treturn &ValidationError{Name: \"execution_time\", err: errors.New(`ent: missing required field \"Revision.execution_time\"`)}\n\t}\n\tif _, ok := _c.mutation.Hash(); !ok {\n\t\treturn &ValidationError{Name: \"hash\", err: errors.New(`ent: missing required field \"Revision.hash\"`)}\n\t}\n\tif _, ok := _c.mutation.OperatorVersion(); !ok {\n\t\treturn &ValidationError{Name: \"operator_version\", err: errors.New(`ent: missing required field \"Revision.operator_version\"`)}\n\t}\n\treturn nil\n}\n\nfunc (_c *RevisionCreate) sqlSave(ctx context.Context) (*Revision, error) {\n\tif err := _c.check(); err != nil {\n\t\treturn nil, err\n\t}\n\t_node, _spec := _c.createSpec()\n\tif err := sqlgraph.CreateNode(ctx, _c.driver, _spec); err != nil {\n\t\tif sqlgraph.IsConstraintError(err) {\n\t\t\terr = &ConstraintError{msg: err.Error(), wrap: err}\n\t\t}\n\t\treturn nil, err\n\t}\n\tif _spec.ID.Value != nil {\n\t\tif id, ok := _spec.ID.Value.(string); ok {\n\t\t\t_node.ID = id\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"unexpected Revision.ID type: %T\", _spec.ID.Value)\n\t\t}\n\t}\n\t_c.mutation.id = &_node.ID\n\t_c.mutation.done = true\n\treturn _node, nil\n}\n\nfunc (_c *RevisionCreate) createSpec() (*Revision, *sqlgraph.CreateSpec) {\n\tvar (\n\t\t_node = &Revision{config: _c.config}\n\t\t_spec = sqlgraph.NewCreateSpec(revision.Table, sqlgraph.NewFieldSpec(revision.FieldID, field.TypeString))\n\t)\n\t_spec.Schema = _c.schemaConfig.Revision\n\t_spec.OnConflict = _c.conflict\n\tif id, ok := _c.mutation.ID(); ok {\n\t\t_node.ID = id\n\t\t_spec.ID.Value = id\n\t}\n\tif value, ok := _c.mutation.Description(); ok {\n\t\t_spec.SetField(revision.FieldDescription, field.TypeString, value)\n\t\t_node.Description = value\n\t}\n\tif value, ok := _c.mutation.GetType(); ok {\n\t\t_spec.SetField(revision.FieldType, field.TypeUint, value)\n\t\t_node.Type = value\n\t}\n\tif value, ok := _c.mutation.Applied(); ok {\n\t\t_spec.SetField(revision.FieldApplied, field.TypeInt, value)\n\t\t_node.Applied = value\n\t}\n\tif value, ok := _c.mutation.Total(); ok {\n\t\t_spec.SetField(revision.FieldTotal, field.TypeInt, value)\n\t\t_node.Total = value\n\t}\n\tif value, ok := _c.mutation.ExecutedAt(); ok {\n\t\t_spec.SetField(revision.FieldExecutedAt, field.TypeTime, value)\n\t\t_node.ExecutedAt = value\n\t}\n\tif value, ok := _c.mutation.ExecutionTime(); ok {\n\t\t_spec.SetField(revision.FieldExecutionTime, field.TypeInt64, value)\n\t\t_node.ExecutionTime = value\n\t}\n\tif value, ok := _c.mutation.Error(); ok {\n\t\t_spec.SetField(revision.FieldError, field.TypeString, value)\n\t\t_node.Error = value\n\t}\n\tif value, ok := _c.mutation.ErrorStmt(); ok {\n\t\t_spec.SetField(revision.FieldErrorStmt, field.TypeString, value)\n\t\t_node.ErrorStmt = value\n\t}\n\tif value, ok := _c.mutation.Hash(); ok {\n\t\t_spec.SetField(revision.FieldHash, field.TypeString, value)\n\t\t_node.Hash = value\n\t}\n\tif value, ok := _c.mutation.PartialHashes(); ok {\n\t\t_spec.SetField(revision.FieldPartialHashes, field.TypeJSON, value)\n\t\t_node.PartialHashes = value\n\t}\n\tif value, ok := _c.mutation.OperatorVersion(); ok {\n\t\t_spec.SetField(revision.FieldOperatorVersion, field.TypeString, value)\n\t\t_node.OperatorVersion = value\n\t}\n\treturn _node, _spec\n}\n\n// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause\n// of the `INSERT` statement. For example:\n//\n//\tclient.Revision.Create().\n//\t\tSetDescription(v).\n//\t\tOnConflict(\n//\t\t\t// Update the row with the new values\n//\t\t\t// the was proposed for insertion.\n//\t\t\tsql.ResolveWithNewValues(),\n//\t\t).\n//\t\t// Override some of the fields with custom\n//\t\t// update values.\n//\t\tUpdate(func(u *ent.RevisionUpsert) {\n//\t\t\tSetDescription(v+v).\n//\t\t}).\n//\t\tExec(ctx)\nfunc (_c *RevisionCreate) OnConflict(opts ...sql.ConflictOption) *RevisionUpsertOne {\n\t_c.conflict = opts\n\treturn &RevisionUpsertOne{\n\t\tcreate: _c,\n\t}\n}\n\n// OnConflictColumns calls `OnConflict` and configures the columns\n// as conflict target. Using this option is equivalent to using:\n//\n//\tclient.Revision.Create().\n//\t\tOnConflict(sql.ConflictColumns(columns...)).\n//\t\tExec(ctx)\nfunc (_c *RevisionCreate) OnConflictColumns(columns ...string) *RevisionUpsertOne {\n\t_c.conflict = append(_c.conflict, sql.ConflictColumns(columns...))\n\treturn &RevisionUpsertOne{\n\t\tcreate: _c,\n\t}\n}\n\ntype (\n\t// RevisionUpsertOne is the builder for \"upsert\"-ing\n\t//  one Revision node.\n\tRevisionUpsertOne struct {\n\t\tcreate *RevisionCreate\n\t}\n\n\t// RevisionUpsert is the \"OnConflict\" setter.\n\tRevisionUpsert struct {\n\t\t*sql.UpdateSet\n\t}\n)\n\n// SetType sets the \"type\" field.\nfunc (u *RevisionUpsert) SetType(v migrate.RevisionType) *RevisionUpsert {\n\tu.Set(revision.FieldType, v)\n\treturn u\n}\n\n// UpdateType sets the \"type\" field to the value that was provided on create.\nfunc (u *RevisionUpsert) UpdateType() *RevisionUpsert {\n\tu.SetExcluded(revision.FieldType)\n\treturn u\n}\n\n// AddType adds v to the \"type\" field.\nfunc (u *RevisionUpsert) AddType(v migrate.RevisionType) *RevisionUpsert {\n\tu.Add(revision.FieldType, v)\n\treturn u\n}\n\n// SetApplied sets the \"applied\" field.\nfunc (u *RevisionUpsert) SetApplied(v int) *RevisionUpsert {\n\tu.Set(revision.FieldApplied, v)\n\treturn u\n}\n\n// UpdateApplied sets the \"applied\" field to the value that was provided on create.\nfunc (u *RevisionUpsert) UpdateApplied() *RevisionUpsert {\n\tu.SetExcluded(revision.FieldApplied)\n\treturn u\n}\n\n// AddApplied adds v to the \"applied\" field.\nfunc (u *RevisionUpsert) AddApplied(v int) *RevisionUpsert {\n\tu.Add(revision.FieldApplied, v)\n\treturn u\n}\n\n// SetTotal sets the \"total\" field.\nfunc (u *RevisionUpsert) SetTotal(v int) *RevisionUpsert {\n\tu.Set(revision.FieldTotal, v)\n\treturn u\n}\n\n// UpdateTotal sets the \"total\" field to the value that was provided on create.\nfunc (u *RevisionUpsert) UpdateTotal() *RevisionUpsert {\n\tu.SetExcluded(revision.FieldTotal)\n\treturn u\n}\n\n// AddTotal adds v to the \"total\" field.\nfunc (u *RevisionUpsert) AddTotal(v int) *RevisionUpsert {\n\tu.Add(revision.FieldTotal, v)\n\treturn u\n}\n\n// SetExecutionTime sets the \"execution_time\" field.\nfunc (u *RevisionUpsert) SetExecutionTime(v time.Duration) *RevisionUpsert {\n\tu.Set(revision.FieldExecutionTime, v)\n\treturn u\n}\n\n// UpdateExecutionTime sets the \"execution_time\" field to the value that was provided on create.\nfunc (u *RevisionUpsert) UpdateExecutionTime() *RevisionUpsert {\n\tu.SetExcluded(revision.FieldExecutionTime)\n\treturn u\n}\n\n// AddExecutionTime adds v to the \"execution_time\" field.\nfunc (u *RevisionUpsert) AddExecutionTime(v time.Duration) *RevisionUpsert {\n\tu.Add(revision.FieldExecutionTime, v)\n\treturn u\n}\n\n// SetError sets the \"error\" field.\nfunc (u *RevisionUpsert) SetError(v string) *RevisionUpsert {\n\tu.Set(revision.FieldError, v)\n\treturn u\n}\n\n// UpdateError sets the \"error\" field to the value that was provided on create.\nfunc (u *RevisionUpsert) UpdateError() *RevisionUpsert {\n\tu.SetExcluded(revision.FieldError)\n\treturn u\n}\n\n// ClearError clears the value of the \"error\" field.\nfunc (u *RevisionUpsert) ClearError() *RevisionUpsert {\n\tu.SetNull(revision.FieldError)\n\treturn u\n}\n\n// SetErrorStmt sets the \"error_stmt\" field.\nfunc (u *RevisionUpsert) SetErrorStmt(v string) *RevisionUpsert {\n\tu.Set(revision.FieldErrorStmt, v)\n\treturn u\n}\n\n// UpdateErrorStmt sets the \"error_stmt\" field to the value that was provided on create.\nfunc (u *RevisionUpsert) UpdateErrorStmt() *RevisionUpsert {\n\tu.SetExcluded(revision.FieldErrorStmt)\n\treturn u\n}\n\n// ClearErrorStmt clears the value of the \"error_stmt\" field.\nfunc (u *RevisionUpsert) ClearErrorStmt() *RevisionUpsert {\n\tu.SetNull(revision.FieldErrorStmt)\n\treturn u\n}\n\n// SetHash sets the \"hash\" field.\nfunc (u *RevisionUpsert) SetHash(v string) *RevisionUpsert {\n\tu.Set(revision.FieldHash, v)\n\treturn u\n}\n\n// UpdateHash sets the \"hash\" field to the value that was provided on create.\nfunc (u *RevisionUpsert) UpdateHash() *RevisionUpsert {\n\tu.SetExcluded(revision.FieldHash)\n\treturn u\n}\n\n// SetPartialHashes sets the \"partial_hashes\" field.\nfunc (u *RevisionUpsert) SetPartialHashes(v []string) *RevisionUpsert {\n\tu.Set(revision.FieldPartialHashes, v)\n\treturn u\n}\n\n// UpdatePartialHashes sets the \"partial_hashes\" field to the value that was provided on create.\nfunc (u *RevisionUpsert) UpdatePartialHashes() *RevisionUpsert {\n\tu.SetExcluded(revision.FieldPartialHashes)\n\treturn u\n}\n\n// ClearPartialHashes clears the value of the \"partial_hashes\" field.\nfunc (u *RevisionUpsert) ClearPartialHashes() *RevisionUpsert {\n\tu.SetNull(revision.FieldPartialHashes)\n\treturn u\n}\n\n// SetOperatorVersion sets the \"operator_version\" field.\nfunc (u *RevisionUpsert) SetOperatorVersion(v string) *RevisionUpsert {\n\tu.Set(revision.FieldOperatorVersion, v)\n\treturn u\n}\n\n// UpdateOperatorVersion sets the \"operator_version\" field to the value that was provided on create.\nfunc (u *RevisionUpsert) UpdateOperatorVersion() *RevisionUpsert {\n\tu.SetExcluded(revision.FieldOperatorVersion)\n\treturn u\n}\n\n// UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field.\n// Using this option is equivalent to using:\n//\n//\tclient.Revision.Create().\n//\t\tOnConflict(\n//\t\t\tsql.ResolveWithNewValues(),\n//\t\t\tsql.ResolveWith(func(u *sql.UpdateSet) {\n//\t\t\t\tu.SetIgnore(revision.FieldID)\n//\t\t\t}),\n//\t\t).\n//\t\tExec(ctx)\nfunc (u *RevisionUpsertOne) UpdateNewValues() *RevisionUpsertOne {\n\tu.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())\n\tu.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {\n\t\tif _, exists := u.create.mutation.ID(); exists {\n\t\t\ts.SetIgnore(revision.FieldID)\n\t\t}\n\t\tif _, exists := u.create.mutation.Description(); exists {\n\t\t\ts.SetIgnore(revision.FieldDescription)\n\t\t}\n\t\tif _, exists := u.create.mutation.ExecutedAt(); exists {\n\t\t\ts.SetIgnore(revision.FieldExecutedAt)\n\t\t}\n\t}))\n\treturn u\n}\n\n// Ignore sets each column to itself in case of conflict.\n// Using this option is equivalent to using:\n//\n//\tclient.Revision.Create().\n//\t    OnConflict(sql.ResolveWithIgnore()).\n//\t    Exec(ctx)\nfunc (u *RevisionUpsertOne) Ignore() *RevisionUpsertOne {\n\tu.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())\n\treturn u\n}\n\n// DoNothing configures the conflict_action to `DO NOTHING`.\n// Supported only by SQLite and PostgreSQL.\nfunc (u *RevisionUpsertOne) DoNothing() *RevisionUpsertOne {\n\tu.create.conflict = append(u.create.conflict, sql.DoNothing())\n\treturn u\n}\n\n// Update allows overriding fields `UPDATE` values. See the RevisionCreate.OnConflict\n// documentation for more info.\nfunc (u *RevisionUpsertOne) Update(set func(*RevisionUpsert)) *RevisionUpsertOne {\n\tu.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {\n\t\tset(&RevisionUpsert{UpdateSet: update})\n\t}))\n\treturn u\n}\n\n// SetType sets the \"type\" field.\nfunc (u *RevisionUpsertOne) SetType(v migrate.RevisionType) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetType(v)\n\t})\n}\n\n// AddType adds v to the \"type\" field.\nfunc (u *RevisionUpsertOne) AddType(v migrate.RevisionType) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.AddType(v)\n\t})\n}\n\n// UpdateType sets the \"type\" field to the value that was provided on create.\nfunc (u *RevisionUpsertOne) UpdateType() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateType()\n\t})\n}\n\n// SetApplied sets the \"applied\" field.\nfunc (u *RevisionUpsertOne) SetApplied(v int) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetApplied(v)\n\t})\n}\n\n// AddApplied adds v to the \"applied\" field.\nfunc (u *RevisionUpsertOne) AddApplied(v int) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.AddApplied(v)\n\t})\n}\n\n// UpdateApplied sets the \"applied\" field to the value that was provided on create.\nfunc (u *RevisionUpsertOne) UpdateApplied() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateApplied()\n\t})\n}\n\n// SetTotal sets the \"total\" field.\nfunc (u *RevisionUpsertOne) SetTotal(v int) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetTotal(v)\n\t})\n}\n\n// AddTotal adds v to the \"total\" field.\nfunc (u *RevisionUpsertOne) AddTotal(v int) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.AddTotal(v)\n\t})\n}\n\n// UpdateTotal sets the \"total\" field to the value that was provided on create.\nfunc (u *RevisionUpsertOne) UpdateTotal() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateTotal()\n\t})\n}\n\n// SetExecutionTime sets the \"execution_time\" field.\nfunc (u *RevisionUpsertOne) SetExecutionTime(v time.Duration) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetExecutionTime(v)\n\t})\n}\n\n// AddExecutionTime adds v to the \"execution_time\" field.\nfunc (u *RevisionUpsertOne) AddExecutionTime(v time.Duration) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.AddExecutionTime(v)\n\t})\n}\n\n// UpdateExecutionTime sets the \"execution_time\" field to the value that was provided on create.\nfunc (u *RevisionUpsertOne) UpdateExecutionTime() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateExecutionTime()\n\t})\n}\n\n// SetError sets the \"error\" field.\nfunc (u *RevisionUpsertOne) SetError(v string) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetError(v)\n\t})\n}\n\n// UpdateError sets the \"error\" field to the value that was provided on create.\nfunc (u *RevisionUpsertOne) UpdateError() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateError()\n\t})\n}\n\n// ClearError clears the value of the \"error\" field.\nfunc (u *RevisionUpsertOne) ClearError() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.ClearError()\n\t})\n}\n\n// SetErrorStmt sets the \"error_stmt\" field.\nfunc (u *RevisionUpsertOne) SetErrorStmt(v string) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetErrorStmt(v)\n\t})\n}\n\n// UpdateErrorStmt sets the \"error_stmt\" field to the value that was provided on create.\nfunc (u *RevisionUpsertOne) UpdateErrorStmt() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateErrorStmt()\n\t})\n}\n\n// ClearErrorStmt clears the value of the \"error_stmt\" field.\nfunc (u *RevisionUpsertOne) ClearErrorStmt() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.ClearErrorStmt()\n\t})\n}\n\n// SetHash sets the \"hash\" field.\nfunc (u *RevisionUpsertOne) SetHash(v string) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetHash(v)\n\t})\n}\n\n// UpdateHash sets the \"hash\" field to the value that was provided on create.\nfunc (u *RevisionUpsertOne) UpdateHash() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateHash()\n\t})\n}\n\n// SetPartialHashes sets the \"partial_hashes\" field.\nfunc (u *RevisionUpsertOne) SetPartialHashes(v []string) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetPartialHashes(v)\n\t})\n}\n\n// UpdatePartialHashes sets the \"partial_hashes\" field to the value that was provided on create.\nfunc (u *RevisionUpsertOne) UpdatePartialHashes() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdatePartialHashes()\n\t})\n}\n\n// ClearPartialHashes clears the value of the \"partial_hashes\" field.\nfunc (u *RevisionUpsertOne) ClearPartialHashes() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.ClearPartialHashes()\n\t})\n}\n\n// SetOperatorVersion sets the \"operator_version\" field.\nfunc (u *RevisionUpsertOne) SetOperatorVersion(v string) *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetOperatorVersion(v)\n\t})\n}\n\n// UpdateOperatorVersion sets the \"operator_version\" field to the value that was provided on create.\nfunc (u *RevisionUpsertOne) UpdateOperatorVersion() *RevisionUpsertOne {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateOperatorVersion()\n\t})\n}\n\n// Exec executes the query.\nfunc (u *RevisionUpsertOne) Exec(ctx context.Context) error {\n\tif len(u.create.conflict) == 0 {\n\t\treturn errors.New(\"ent: missing options for RevisionCreate.OnConflict\")\n\t}\n\treturn u.create.Exec(ctx)\n}\n\n// ExecX is like Exec, but panics if an error occurs.\nfunc (u *RevisionUpsertOne) ExecX(ctx context.Context) {\n\tif err := u.create.Exec(ctx); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// Exec executes the UPSERT query and returns the inserted/updated ID.\nfunc (u *RevisionUpsertOne) ID(ctx context.Context) (id string, err error) {\n\tif u.create.driver.Dialect() == dialect.MySQL {\n\t\t// In case of \"ON CONFLICT\", there is no way to get back non-numeric ID\n\t\t// fields from the database since MySQL does not support the RETURNING clause.\n\t\treturn id, errors.New(\"ent: RevisionUpsertOne.ID is not supported by MySQL driver. Use RevisionUpsertOne.Exec instead\")\n\t}\n\tnode, err := u.create.Save(ctx)\n\tif err != nil {\n\t\treturn id, err\n\t}\n\treturn node.ID, nil\n}\n\n// IDX is like ID, but panics if an error occurs.\nfunc (u *RevisionUpsertOne) IDX(ctx context.Context) string {\n\tid, err := u.ID(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn id\n}\n\n// RevisionCreateBulk is the builder for creating many Revision entities in bulk.\ntype RevisionCreateBulk struct {\n\tconfig\n\terr      error\n\tbuilders []*RevisionCreate\n\tconflict []sql.ConflictOption\n}\n\n// Save creates the Revision entities in the database.\nfunc (_c *RevisionCreateBulk) Save(ctx context.Context) ([]*Revision, error) {\n\tif _c.err != nil {\n\t\treturn nil, _c.err\n\t}\n\tspecs := make([]*sqlgraph.CreateSpec, len(_c.builders))\n\tnodes := make([]*Revision, len(_c.builders))\n\tmutators := make([]Mutator, len(_c.builders))\n\tfor i := range _c.builders {\n\t\tfunc(i int, root context.Context) {\n\t\t\tbuilder := _c.builders[i]\n\t\t\tbuilder.defaults()\n\t\t\tvar mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {\n\t\t\t\tmutation, ok := m.(*RevisionMutation)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, fmt.Errorf(\"unexpected mutation type %T\", m)\n\t\t\t\t}\n\t\t\t\tif err := builder.check(); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tbuilder.mutation = mutation\n\t\t\t\tvar err error\n\t\t\t\tnodes[i], specs[i] = builder.createSpec()\n\t\t\t\tif i < len(mutators)-1 {\n\t\t\t\t\t_, err = mutators[i+1].Mutate(root, _c.builders[i+1].mutation)\n\t\t\t\t} else {\n\t\t\t\t\tspec := &sqlgraph.BatchCreateSpec{Nodes: specs}\n\t\t\t\t\tspec.OnConflict = _c.conflict\n\t\t\t\t\t// Invoke the actual operation on the latest mutation in the chain.\n\t\t\t\t\tif err = sqlgraph.BatchCreate(ctx, _c.driver, spec); err != nil {\n\t\t\t\t\t\tif sqlgraph.IsConstraintError(err) {\n\t\t\t\t\t\t\terr = &ConstraintError{msg: err.Error(), wrap: err}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tmutation.id = &nodes[i].ID\n\t\t\t\tmutation.done = true\n\t\t\t\treturn nodes[i], nil\n\t\t\t})\n\t\t\tfor i := len(builder.hooks) - 1; i >= 0; i-- {\n\t\t\t\tmut = builder.hooks[i](mut)\n\t\t\t}\n\t\t\tmutators[i] = mut\n\t\t}(i, ctx)\n\t}\n\tif len(mutators) > 0 {\n\t\tif _, err := mutators[0].Mutate(ctx, _c.builders[0].mutation); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn nodes, nil\n}\n\n// SaveX is like Save, but panics if an error occurs.\nfunc (_c *RevisionCreateBulk) SaveX(ctx context.Context) []*Revision {\n\tv, err := _c.Save(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn v\n}\n\n// Exec executes the query.\nfunc (_c *RevisionCreateBulk) Exec(ctx context.Context) error {\n\t_, err := _c.Save(ctx)\n\treturn err\n}\n\n// ExecX is like Exec, but panics if an error occurs.\nfunc (_c *RevisionCreateBulk) ExecX(ctx context.Context) {\n\tif err := _c.Exec(ctx); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause\n// of the `INSERT` statement. For example:\n//\n//\tclient.Revision.CreateBulk(builders...).\n//\t\tOnConflict(\n//\t\t\t// Update the row with the new values\n//\t\t\t// the was proposed for insertion.\n//\t\t\tsql.ResolveWithNewValues(),\n//\t\t).\n//\t\t// Override some of the fields with custom\n//\t\t// update values.\n//\t\tUpdate(func(u *ent.RevisionUpsert) {\n//\t\t\tSetDescription(v+v).\n//\t\t}).\n//\t\tExec(ctx)\nfunc (_c *RevisionCreateBulk) OnConflict(opts ...sql.ConflictOption) *RevisionUpsertBulk {\n\t_c.conflict = opts\n\treturn &RevisionUpsertBulk{\n\t\tcreate: _c,\n\t}\n}\n\n// OnConflictColumns calls `OnConflict` and configures the columns\n// as conflict target. Using this option is equivalent to using:\n//\n//\tclient.Revision.Create().\n//\t\tOnConflict(sql.ConflictColumns(columns...)).\n//\t\tExec(ctx)\nfunc (_c *RevisionCreateBulk) OnConflictColumns(columns ...string) *RevisionUpsertBulk {\n\t_c.conflict = append(_c.conflict, sql.ConflictColumns(columns...))\n\treturn &RevisionUpsertBulk{\n\t\tcreate: _c,\n\t}\n}\n\n// RevisionUpsertBulk is the builder for \"upsert\"-ing\n// a bulk of Revision nodes.\ntype RevisionUpsertBulk struct {\n\tcreate *RevisionCreateBulk\n}\n\n// UpdateNewValues updates the mutable fields using the new values that\n// were set on create. Using this option is equivalent to using:\n//\n//\tclient.Revision.Create().\n//\t\tOnConflict(\n//\t\t\tsql.ResolveWithNewValues(),\n//\t\t\tsql.ResolveWith(func(u *sql.UpdateSet) {\n//\t\t\t\tu.SetIgnore(revision.FieldID)\n//\t\t\t}),\n//\t\t).\n//\t\tExec(ctx)\nfunc (u *RevisionUpsertBulk) UpdateNewValues() *RevisionUpsertBulk {\n\tu.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues())\n\tu.create.conflict = append(u.create.conflict, sql.ResolveWith(func(s *sql.UpdateSet) {\n\t\tfor _, b := range u.create.builders {\n\t\t\tif _, exists := b.mutation.ID(); exists {\n\t\t\t\ts.SetIgnore(revision.FieldID)\n\t\t\t}\n\t\t\tif _, exists := b.mutation.Description(); exists {\n\t\t\t\ts.SetIgnore(revision.FieldDescription)\n\t\t\t}\n\t\t\tif _, exists := b.mutation.ExecutedAt(); exists {\n\t\t\t\ts.SetIgnore(revision.FieldExecutedAt)\n\t\t\t}\n\t\t}\n\t}))\n\treturn u\n}\n\n// Ignore sets each column to itself in case of conflict.\n// Using this option is equivalent to using:\n//\n//\tclient.Revision.Create().\n//\t\tOnConflict(sql.ResolveWithIgnore()).\n//\t\tExec(ctx)\nfunc (u *RevisionUpsertBulk) Ignore() *RevisionUpsertBulk {\n\tu.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore())\n\treturn u\n}\n\n// DoNothing configures the conflict_action to `DO NOTHING`.\n// Supported only by SQLite and PostgreSQL.\nfunc (u *RevisionUpsertBulk) DoNothing() *RevisionUpsertBulk {\n\tu.create.conflict = append(u.create.conflict, sql.DoNothing())\n\treturn u\n}\n\n// Update allows overriding fields `UPDATE` values. See the RevisionCreateBulk.OnConflict\n// documentation for more info.\nfunc (u *RevisionUpsertBulk) Update(set func(*RevisionUpsert)) *RevisionUpsertBulk {\n\tu.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {\n\t\tset(&RevisionUpsert{UpdateSet: update})\n\t}))\n\treturn u\n}\n\n// SetType sets the \"type\" field.\nfunc (u *RevisionUpsertBulk) SetType(v migrate.RevisionType) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetType(v)\n\t})\n}\n\n// AddType adds v to the \"type\" field.\nfunc (u *RevisionUpsertBulk) AddType(v migrate.RevisionType) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.AddType(v)\n\t})\n}\n\n// UpdateType sets the \"type\" field to the value that was provided on create.\nfunc (u *RevisionUpsertBulk) UpdateType() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateType()\n\t})\n}\n\n// SetApplied sets the \"applied\" field.\nfunc (u *RevisionUpsertBulk) SetApplied(v int) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetApplied(v)\n\t})\n}\n\n// AddApplied adds v to the \"applied\" field.\nfunc (u *RevisionUpsertBulk) AddApplied(v int) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.AddApplied(v)\n\t})\n}\n\n// UpdateApplied sets the \"applied\" field to the value that was provided on create.\nfunc (u *RevisionUpsertBulk) UpdateApplied() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateApplied()\n\t})\n}\n\n// SetTotal sets the \"total\" field.\nfunc (u *RevisionUpsertBulk) SetTotal(v int) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetTotal(v)\n\t})\n}\n\n// AddTotal adds v to the \"total\" field.\nfunc (u *RevisionUpsertBulk) AddTotal(v int) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.AddTotal(v)\n\t})\n}\n\n// UpdateTotal sets the \"total\" field to the value that was provided on create.\nfunc (u *RevisionUpsertBulk) UpdateTotal() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateTotal()\n\t})\n}\n\n// SetExecutionTime sets the \"execution_time\" field.\nfunc (u *RevisionUpsertBulk) SetExecutionTime(v time.Duration) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetExecutionTime(v)\n\t})\n}\n\n// AddExecutionTime adds v to the \"execution_time\" field.\nfunc (u *RevisionUpsertBulk) AddExecutionTime(v time.Duration) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.AddExecutionTime(v)\n\t})\n}\n\n// UpdateExecutionTime sets the \"execution_time\" field to the value that was provided on create.\nfunc (u *RevisionUpsertBulk) UpdateExecutionTime() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateExecutionTime()\n\t})\n}\n\n// SetError sets the \"error\" field.\nfunc (u *RevisionUpsertBulk) SetError(v string) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetError(v)\n\t})\n}\n\n// UpdateError sets the \"error\" field to the value that was provided on create.\nfunc (u *RevisionUpsertBulk) UpdateError() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateError()\n\t})\n}\n\n// ClearError clears the value of the \"error\" field.\nfunc (u *RevisionUpsertBulk) ClearError() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.ClearError()\n\t})\n}\n\n// SetErrorStmt sets the \"error_stmt\" field.\nfunc (u *RevisionUpsertBulk) SetErrorStmt(v string) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetErrorStmt(v)\n\t})\n}\n\n// UpdateErrorStmt sets the \"error_stmt\" field to the value that was provided on create.\nfunc (u *RevisionUpsertBulk) UpdateErrorStmt() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateErrorStmt()\n\t})\n}\n\n// ClearErrorStmt clears the value of the \"error_stmt\" field.\nfunc (u *RevisionUpsertBulk) ClearErrorStmt() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.ClearErrorStmt()\n\t})\n}\n\n// SetHash sets the \"hash\" field.\nfunc (u *RevisionUpsertBulk) SetHash(v string) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetHash(v)\n\t})\n}\n\n// UpdateHash sets the \"hash\" field to the value that was provided on create.\nfunc (u *RevisionUpsertBulk) UpdateHash() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateHash()\n\t})\n}\n\n// SetPartialHashes sets the \"partial_hashes\" field.\nfunc (u *RevisionUpsertBulk) SetPartialHashes(v []string) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetPartialHashes(v)\n\t})\n}\n\n// UpdatePartialHashes sets the \"partial_hashes\" field to the value that was provided on create.\nfunc (u *RevisionUpsertBulk) UpdatePartialHashes() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdatePartialHashes()\n\t})\n}\n\n// ClearPartialHashes clears the value of the \"partial_hashes\" field.\nfunc (u *RevisionUpsertBulk) ClearPartialHashes() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.ClearPartialHashes()\n\t})\n}\n\n// SetOperatorVersion sets the \"operator_version\" field.\nfunc (u *RevisionUpsertBulk) SetOperatorVersion(v string) *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.SetOperatorVersion(v)\n\t})\n}\n\n// UpdateOperatorVersion sets the \"operator_version\" field to the value that was provided on create.\nfunc (u *RevisionUpsertBulk) UpdateOperatorVersion() *RevisionUpsertBulk {\n\treturn u.Update(func(s *RevisionUpsert) {\n\t\ts.UpdateOperatorVersion()\n\t})\n}\n\n// Exec executes the query.\nfunc (u *RevisionUpsertBulk) Exec(ctx context.Context) error {\n\tif u.create.err != nil {\n\t\treturn u.create.err\n\t}\n\tfor i, b := range u.create.builders {\n\t\tif len(b.conflict) != 0 {\n\t\t\treturn fmt.Errorf(\"ent: OnConflict was set for builder %d. Set it on the RevisionCreateBulk instead\", i)\n\t\t}\n\t}\n\tif len(u.create.conflict) == 0 {\n\t\treturn errors.New(\"ent: missing options for RevisionCreateBulk.OnConflict\")\n\t}\n\treturn u.create.Exec(ctx)\n}\n\n// ExecX is like Exec, but panics if an error occurs.\nfunc (u *RevisionUpsertBulk) ExecX(ctx context.Context) {\n\tif err := u.create.Exec(ctx); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/revision_delete.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport (\n\t\"context\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/internal\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/predicate\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"entgo.io/ent/dialect/sql\"\n\t\"entgo.io/ent/dialect/sql/sqlgraph\"\n\t\"entgo.io/ent/schema/field\"\n)\n\n// RevisionDelete is the builder for deleting a Revision entity.\ntype RevisionDelete struct {\n\tconfig\n\thooks    []Hook\n\tmutation *RevisionMutation\n}\n\n// Where appends a list predicates to the RevisionDelete builder.\nfunc (_d *RevisionDelete) Where(ps ...predicate.Revision) *RevisionDelete {\n\t_d.mutation.Where(ps...)\n\treturn _d\n}\n\n// Exec executes the deletion query and returns how many vertices were deleted.\nfunc (_d *RevisionDelete) Exec(ctx context.Context) (int, error) {\n\treturn withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)\n}\n\n// ExecX is like Exec, but panics if an error occurs.\nfunc (_d *RevisionDelete) ExecX(ctx context.Context) int {\n\tn, err := _d.Exec(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn n\n}\n\nfunc (_d *RevisionDelete) sqlExec(ctx context.Context) (int, error) {\n\t_spec := sqlgraph.NewDeleteSpec(revision.Table, sqlgraph.NewFieldSpec(revision.FieldID, field.TypeString))\n\t_spec.Node.Schema = _d.schemaConfig.Revision\n\tctx = internal.NewSchemaConfigContext(ctx, _d.schemaConfig)\n\tif ps := _d.mutation.predicates; len(ps) > 0 {\n\t\t_spec.Predicate = func(selector *sql.Selector) {\n\t\t\tfor i := range ps {\n\t\t\t\tps[i](selector)\n\t\t\t}\n\t\t}\n\t}\n\taffected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)\n\tif err != nil && sqlgraph.IsConstraintError(err) {\n\t\terr = &ConstraintError{msg: err.Error(), wrap: err}\n\t}\n\t_d.mutation.done = true\n\treturn affected, err\n}\n\n// RevisionDeleteOne is the builder for deleting a single Revision entity.\ntype RevisionDeleteOne struct {\n\t_d *RevisionDelete\n}\n\n// Where appends a list predicates to the RevisionDelete builder.\nfunc (_d *RevisionDeleteOne) Where(ps ...predicate.Revision) *RevisionDeleteOne {\n\t_d._d.mutation.Where(ps...)\n\treturn _d\n}\n\n// Exec executes the deletion query.\nfunc (_d *RevisionDeleteOne) Exec(ctx context.Context) error {\n\tn, err := _d._d.Exec(ctx)\n\tswitch {\n\tcase err != nil:\n\t\treturn err\n\tcase n == 0:\n\t\treturn &NotFoundError{revision.Label}\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// ExecX is like Exec, but panics if an error occurs.\nfunc (_d *RevisionDeleteOne) ExecX(ctx context.Context) {\n\tif err := _d.Exec(ctx); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/revision_query.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/internal\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/predicate\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"entgo.io/ent\"\n\t\"entgo.io/ent/dialect/sql\"\n\t\"entgo.io/ent/dialect/sql/sqlgraph\"\n\t\"entgo.io/ent/schema/field\"\n)\n\n// RevisionQuery is the builder for querying Revision entities.\ntype RevisionQuery struct {\n\tconfig\n\tctx        *QueryContext\n\torder      []revision.OrderOption\n\tinters     []Interceptor\n\tpredicates []predicate.Revision\n\t// intermediate query (i.e. traversal path).\n\tsql  *sql.Selector\n\tpath func(context.Context) (*sql.Selector, error)\n}\n\n// Where adds a new predicate for the RevisionQuery builder.\nfunc (_q *RevisionQuery) Where(ps ...predicate.Revision) *RevisionQuery {\n\t_q.predicates = append(_q.predicates, ps...)\n\treturn _q\n}\n\n// Limit the number of records to be returned by this query.\nfunc (_q *RevisionQuery) Limit(limit int) *RevisionQuery {\n\t_q.ctx.Limit = &limit\n\treturn _q\n}\n\n// Offset to start from.\nfunc (_q *RevisionQuery) Offset(offset int) *RevisionQuery {\n\t_q.ctx.Offset = &offset\n\treturn _q\n}\n\n// Unique configures the query builder to filter duplicate records on query.\n// By default, unique is set to true, and can be disabled using this method.\nfunc (_q *RevisionQuery) Unique(unique bool) *RevisionQuery {\n\t_q.ctx.Unique = &unique\n\treturn _q\n}\n\n// Order specifies how the records should be ordered.\nfunc (_q *RevisionQuery) Order(o ...revision.OrderOption) *RevisionQuery {\n\t_q.order = append(_q.order, o...)\n\treturn _q\n}\n\n// First returns the first Revision entity from the query.\n// Returns a *NotFoundError when no Revision was found.\nfunc (_q *RevisionQuery) First(ctx context.Context) (*Revision, error) {\n\tnodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(nodes) == 0 {\n\t\treturn nil, &NotFoundError{revision.Label}\n\t}\n\treturn nodes[0], nil\n}\n\n// FirstX is like First, but panics if an error occurs.\nfunc (_q *RevisionQuery) FirstX(ctx context.Context) *Revision {\n\tnode, err := _q.First(ctx)\n\tif err != nil && !IsNotFound(err) {\n\t\tpanic(err)\n\t}\n\treturn node\n}\n\n// FirstID returns the first Revision ID from the query.\n// Returns a *NotFoundError when no Revision ID was found.\nfunc (_q *RevisionQuery) FirstID(ctx context.Context) (id string, err error) {\n\tvar ids []string\n\tif ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil {\n\t\treturn\n\t}\n\tif len(ids) == 0 {\n\t\terr = &NotFoundError{revision.Label}\n\t\treturn\n\t}\n\treturn ids[0], nil\n}\n\n// FirstIDX is like FirstID, but panics if an error occurs.\nfunc (_q *RevisionQuery) FirstIDX(ctx context.Context) string {\n\tid, err := _q.FirstID(ctx)\n\tif err != nil && !IsNotFound(err) {\n\t\tpanic(err)\n\t}\n\treturn id\n}\n\n// Only returns a single Revision entity found by the query, ensuring it only returns one.\n// Returns a *NotSingularError when more than one Revision entity is found.\n// Returns a *NotFoundError when no Revision entities are found.\nfunc (_q *RevisionQuery) Only(ctx context.Context) (*Revision, error) {\n\tnodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch len(nodes) {\n\tcase 1:\n\t\treturn nodes[0], nil\n\tcase 0:\n\t\treturn nil, &NotFoundError{revision.Label}\n\tdefault:\n\t\treturn nil, &NotSingularError{revision.Label}\n\t}\n}\n\n// OnlyX is like Only, but panics if an error occurs.\nfunc (_q *RevisionQuery) OnlyX(ctx context.Context) *Revision {\n\tnode, err := _q.Only(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn node\n}\n\n// OnlyID is like Only, but returns the only Revision ID in the query.\n// Returns a *NotSingularError when more than one Revision ID is found.\n// Returns a *NotFoundError when no entities are found.\nfunc (_q *RevisionQuery) OnlyID(ctx context.Context) (id string, err error) {\n\tvar ids []string\n\tif ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil {\n\t\treturn\n\t}\n\tswitch len(ids) {\n\tcase 1:\n\t\tid = ids[0]\n\tcase 0:\n\t\terr = &NotFoundError{revision.Label}\n\tdefault:\n\t\terr = &NotSingularError{revision.Label}\n\t}\n\treturn\n}\n\n// OnlyIDX is like OnlyID, but panics if an error occurs.\nfunc (_q *RevisionQuery) OnlyIDX(ctx context.Context) string {\n\tid, err := _q.OnlyID(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn id\n}\n\n// All executes the query and returns a list of Revisions.\nfunc (_q *RevisionQuery) All(ctx context.Context) ([]*Revision, error) {\n\tctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll)\n\tif err := _q.prepareQuery(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tqr := querierAll[[]*Revision, *RevisionQuery]()\n\treturn withInterceptors[[]*Revision](ctx, _q, qr, _q.inters)\n}\n\n// AllX is like All, but panics if an error occurs.\nfunc (_q *RevisionQuery) AllX(ctx context.Context) []*Revision {\n\tnodes, err := _q.All(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn nodes\n}\n\n// IDs executes the query and returns a list of Revision IDs.\nfunc (_q *RevisionQuery) IDs(ctx context.Context) (ids []string, err error) {\n\tif _q.ctx.Unique == nil && _q.path != nil {\n\t\t_q.Unique(true)\n\t}\n\tctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs)\n\tif err = _q.Select(revision.FieldID).Scan(ctx, &ids); err != nil {\n\t\treturn nil, err\n\t}\n\treturn ids, nil\n}\n\n// IDsX is like IDs, but panics if an error occurs.\nfunc (_q *RevisionQuery) IDsX(ctx context.Context) []string {\n\tids, err := _q.IDs(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn ids\n}\n\n// Count returns the count of the given query.\nfunc (_q *RevisionQuery) Count(ctx context.Context) (int, error) {\n\tctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount)\n\tif err := _q.prepareQuery(ctx); err != nil {\n\t\treturn 0, err\n\t}\n\treturn withInterceptors[int](ctx, _q, querierCount[*RevisionQuery](), _q.inters)\n}\n\n// CountX is like Count, but panics if an error occurs.\nfunc (_q *RevisionQuery) CountX(ctx context.Context) int {\n\tcount, err := _q.Count(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn count\n}\n\n// Exist returns true if the query has elements in the graph.\nfunc (_q *RevisionQuery) Exist(ctx context.Context) (bool, error) {\n\tctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist)\n\tswitch _, err := _q.FirstID(ctx); {\n\tcase IsNotFound(err):\n\t\treturn false, nil\n\tcase err != nil:\n\t\treturn false, fmt.Errorf(\"ent: check existence: %w\", err)\n\tdefault:\n\t\treturn true, nil\n\t}\n}\n\n// ExistX is like Exist, but panics if an error occurs.\nfunc (_q *RevisionQuery) ExistX(ctx context.Context) bool {\n\texist, err := _q.Exist(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn exist\n}\n\n// Clone returns a duplicate of the RevisionQuery builder, including all associated steps. It can be\n// used to prepare common query builders and use them differently after the clone is made.\nfunc (_q *RevisionQuery) Clone() *RevisionQuery {\n\tif _q == nil {\n\t\treturn nil\n\t}\n\treturn &RevisionQuery{\n\t\tconfig:     _q.config,\n\t\tctx:        _q.ctx.Clone(),\n\t\torder:      append([]revision.OrderOption{}, _q.order...),\n\t\tinters:     append([]Interceptor{}, _q.inters...),\n\t\tpredicates: append([]predicate.Revision{}, _q.predicates...),\n\t\t// clone intermediate query.\n\t\tsql:  _q.sql.Clone(),\n\t\tpath: _q.path,\n\t}\n}\n\n// GroupBy is used to group vertices by one or more fields/columns.\n// It is often used with aggregate functions, like: count, max, mean, min, sum.\n//\n// Example:\n//\n//\tvar v []struct {\n//\t\tDescription string `json:\"description,omitempty\"`\n//\t\tCount int `json:\"count,omitempty\"`\n//\t}\n//\n//\tclient.Revision.Query().\n//\t\tGroupBy(revision.FieldDescription).\n//\t\tAggregate(ent.Count()).\n//\t\tScan(ctx, &v)\nfunc (_q *RevisionQuery) GroupBy(field string, fields ...string) *RevisionGroupBy {\n\t_q.ctx.Fields = append([]string{field}, fields...)\n\tgrbuild := &RevisionGroupBy{build: _q}\n\tgrbuild.flds = &_q.ctx.Fields\n\tgrbuild.label = revision.Label\n\tgrbuild.scan = grbuild.Scan\n\treturn grbuild\n}\n\n// Select allows the selection one or more fields/columns for the given query,\n// instead of selecting all fields in the entity.\n//\n// Example:\n//\n//\tvar v []struct {\n//\t\tDescription string `json:\"description,omitempty\"`\n//\t}\n//\n//\tclient.Revision.Query().\n//\t\tSelect(revision.FieldDescription).\n//\t\tScan(ctx, &v)\nfunc (_q *RevisionQuery) Select(fields ...string) *RevisionSelect {\n\t_q.ctx.Fields = append(_q.ctx.Fields, fields...)\n\tsbuild := &RevisionSelect{RevisionQuery: _q}\n\tsbuild.label = revision.Label\n\tsbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan\n\treturn sbuild\n}\n\n// Aggregate returns a RevisionSelect configured with the given aggregations.\nfunc (_q *RevisionQuery) Aggregate(fns ...AggregateFunc) *RevisionSelect {\n\treturn _q.Select().Aggregate(fns...)\n}\n\nfunc (_q *RevisionQuery) prepareQuery(ctx context.Context) error {\n\tfor _, inter := range _q.inters {\n\t\tif inter == nil {\n\t\t\treturn fmt.Errorf(\"ent: uninitialized interceptor (forgotten import ent/runtime?)\")\n\t\t}\n\t\tif trv, ok := inter.(Traverser); ok {\n\t\t\tif err := trv.Traverse(ctx, _q); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tfor _, f := range _q.ctx.Fields {\n\t\tif !revision.ValidColumn(f) {\n\t\t\treturn &ValidationError{Name: f, err: fmt.Errorf(\"ent: invalid field %q for query\", f)}\n\t\t}\n\t}\n\tif _q.path != nil {\n\t\tprev, err := _q.path(ctx)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t_q.sql = prev\n\t}\n\treturn nil\n}\n\nfunc (_q *RevisionQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Revision, error) {\n\tvar (\n\t\tnodes = []*Revision{}\n\t\t_spec = _q.querySpec()\n\t)\n\t_spec.ScanValues = func(columns []string) ([]any, error) {\n\t\treturn (*Revision).scanValues(nil, columns)\n\t}\n\t_spec.Assign = func(columns []string, values []any) error {\n\t\tnode := &Revision{config: _q.config}\n\t\tnodes = append(nodes, node)\n\t\treturn node.assignValues(columns, values)\n\t}\n\t_spec.Node.Schema = _q.schemaConfig.Revision\n\tctx = internal.NewSchemaConfigContext(ctx, _q.schemaConfig)\n\tfor i := range hooks {\n\t\thooks[i](ctx, _spec)\n\t}\n\tif err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(nodes) == 0 {\n\t\treturn nodes, nil\n\t}\n\treturn nodes, nil\n}\n\nfunc (_q *RevisionQuery) sqlCount(ctx context.Context) (int, error) {\n\t_spec := _q.querySpec()\n\t_spec.Node.Schema = _q.schemaConfig.Revision\n\tctx = internal.NewSchemaConfigContext(ctx, _q.schemaConfig)\n\t_spec.Node.Columns = _q.ctx.Fields\n\tif len(_q.ctx.Fields) > 0 {\n\t\t_spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique\n\t}\n\treturn sqlgraph.CountNodes(ctx, _q.driver, _spec)\n}\n\nfunc (_q *RevisionQuery) querySpec() *sqlgraph.QuerySpec {\n\t_spec := sqlgraph.NewQuerySpec(revision.Table, revision.Columns, sqlgraph.NewFieldSpec(revision.FieldID, field.TypeString))\n\t_spec.From = _q.sql\n\tif unique := _q.ctx.Unique; unique != nil {\n\t\t_spec.Unique = *unique\n\t} else if _q.path != nil {\n\t\t_spec.Unique = true\n\t}\n\tif fields := _q.ctx.Fields; len(fields) > 0 {\n\t\t_spec.Node.Columns = make([]string, 0, len(fields))\n\t\t_spec.Node.Columns = append(_spec.Node.Columns, revision.FieldID)\n\t\tfor i := range fields {\n\t\t\tif fields[i] != revision.FieldID {\n\t\t\t\t_spec.Node.Columns = append(_spec.Node.Columns, fields[i])\n\t\t\t}\n\t\t}\n\t}\n\tif ps := _q.predicates; len(ps) > 0 {\n\t\t_spec.Predicate = func(selector *sql.Selector) {\n\t\t\tfor i := range ps {\n\t\t\t\tps[i](selector)\n\t\t\t}\n\t\t}\n\t}\n\tif limit := _q.ctx.Limit; limit != nil {\n\t\t_spec.Limit = *limit\n\t}\n\tif offset := _q.ctx.Offset; offset != nil {\n\t\t_spec.Offset = *offset\n\t}\n\tif ps := _q.order; len(ps) > 0 {\n\t\t_spec.Order = func(selector *sql.Selector) {\n\t\t\tfor i := range ps {\n\t\t\t\tps[i](selector)\n\t\t\t}\n\t\t}\n\t}\n\treturn _spec\n}\n\nfunc (_q *RevisionQuery) sqlQuery(ctx context.Context) *sql.Selector {\n\tbuilder := sql.Dialect(_q.driver.Dialect())\n\tt1 := builder.Table(revision.Table)\n\tcolumns := _q.ctx.Fields\n\tif len(columns) == 0 {\n\t\tcolumns = revision.Columns\n\t}\n\tselector := builder.Select(t1.Columns(columns...)...).From(t1)\n\tif _q.sql != nil {\n\t\tselector = _q.sql\n\t\tselector.Select(selector.Columns(columns...)...)\n\t}\n\tif _q.ctx.Unique != nil && *_q.ctx.Unique {\n\t\tselector.Distinct()\n\t}\n\tt1.Schema(_q.schemaConfig.Revision)\n\tctx = internal.NewSchemaConfigContext(ctx, _q.schemaConfig)\n\tselector.WithContext(ctx)\n\tfor _, p := range _q.predicates {\n\t\tp(selector)\n\t}\n\tfor _, p := range _q.order {\n\t\tp(selector)\n\t}\n\tif offset := _q.ctx.Offset; offset != nil {\n\t\t// limit is mandatory for offset clause. We start\n\t\t// with default value, and override it below if needed.\n\t\tselector.Offset(*offset).Limit(math.MaxInt32)\n\t}\n\tif limit := _q.ctx.Limit; limit != nil {\n\t\tselector.Limit(*limit)\n\t}\n\treturn selector\n}\n\n// RevisionGroupBy is the group-by builder for Revision entities.\ntype RevisionGroupBy struct {\n\tselector\n\tbuild *RevisionQuery\n}\n\n// Aggregate adds the given aggregation functions to the group-by query.\nfunc (_g *RevisionGroupBy) Aggregate(fns ...AggregateFunc) *RevisionGroupBy {\n\t_g.fns = append(_g.fns, fns...)\n\treturn _g\n}\n\n// Scan applies the selector query and scans the result into the given value.\nfunc (_g *RevisionGroupBy) Scan(ctx context.Context, v any) error {\n\tctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy)\n\tif err := _g.build.prepareQuery(ctx); err != nil {\n\t\treturn err\n\t}\n\treturn scanWithInterceptors[*RevisionQuery, *RevisionGroupBy](ctx, _g.build, _g, _g.build.inters, v)\n}\n\nfunc (_g *RevisionGroupBy) sqlScan(ctx context.Context, root *RevisionQuery, v any) error {\n\tselector := root.sqlQuery(ctx).Select()\n\taggregation := make([]string, 0, len(_g.fns))\n\tfor _, fn := range _g.fns {\n\t\taggregation = append(aggregation, fn(selector))\n\t}\n\tif len(selector.SelectedColumns()) == 0 {\n\t\tcolumns := make([]string, 0, len(*_g.flds)+len(_g.fns))\n\t\tfor _, f := range *_g.flds {\n\t\t\tcolumns = append(columns, selector.C(f))\n\t\t}\n\t\tcolumns = append(columns, aggregation...)\n\t\tselector.Select(columns...)\n\t}\n\tselector.GroupBy(selector.Columns(*_g.flds...)...)\n\tif err := selector.Err(); err != nil {\n\t\treturn err\n\t}\n\trows := &sql.Rows{}\n\tquery, args := selector.Query()\n\tif err := _g.build.driver.Query(ctx, query, args, rows); err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\treturn sql.ScanSlice(rows, v)\n}\n\n// RevisionSelect is the builder for selecting fields of Revision entities.\ntype RevisionSelect struct {\n\t*RevisionQuery\n\tselector\n}\n\n// Aggregate adds the given aggregation functions to the selector query.\nfunc (_s *RevisionSelect) Aggregate(fns ...AggregateFunc) *RevisionSelect {\n\t_s.fns = append(_s.fns, fns...)\n\treturn _s\n}\n\n// Scan applies the selector query and scans the result into the given value.\nfunc (_s *RevisionSelect) Scan(ctx context.Context, v any) error {\n\tctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect)\n\tif err := _s.prepareQuery(ctx); err != nil {\n\t\treturn err\n\t}\n\treturn scanWithInterceptors[*RevisionQuery, *RevisionSelect](ctx, _s.RevisionQuery, _s, _s.inters, v)\n}\n\nfunc (_s *RevisionSelect) sqlScan(ctx context.Context, root *RevisionQuery, v any) error {\n\tselector := root.sqlQuery(ctx)\n\taggregation := make([]string, 0, len(_s.fns))\n\tfor _, fn := range _s.fns {\n\t\taggregation = append(aggregation, fn(selector))\n\t}\n\tswitch n := len(*_s.selector.flds); {\n\tcase n == 0 && len(aggregation) > 0:\n\t\tselector.Select(aggregation...)\n\tcase n != 0 && len(aggregation) > 0:\n\t\tselector.AppendSelect(aggregation...)\n\t}\n\trows := &sql.Rows{}\n\tquery, args := selector.Query()\n\tif err := _s.driver.Query(ctx, query, args, rows); err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\treturn sql.ScanSlice(rows, v)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/revision_update.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/internal\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/predicate\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"entgo.io/ent/dialect/sql\"\n\t\"entgo.io/ent/dialect/sql/sqlgraph\"\n\t\"entgo.io/ent/dialect/sql/sqljson\"\n\t\"entgo.io/ent/schema/field\"\n)\n\n// RevisionUpdate is the builder for updating Revision entities.\ntype RevisionUpdate struct {\n\tconfig\n\thooks    []Hook\n\tmutation *RevisionMutation\n}\n\n// Where appends a list predicates to the RevisionUpdate builder.\nfunc (_u *RevisionUpdate) Where(ps ...predicate.Revision) *RevisionUpdate {\n\t_u.mutation.Where(ps...)\n\treturn _u\n}\n\n// SetType sets the \"type\" field.\nfunc (_u *RevisionUpdate) SetType(v migrate.RevisionType) *RevisionUpdate {\n\t_u.mutation.ResetType()\n\t_u.mutation.SetType(v)\n\treturn _u\n}\n\n// SetNillableType sets the \"type\" field if the given value is not nil.\nfunc (_u *RevisionUpdate) SetNillableType(v *migrate.RevisionType) *RevisionUpdate {\n\tif v != nil {\n\t\t_u.SetType(*v)\n\t}\n\treturn _u\n}\n\n// AddType adds value to the \"type\" field.\nfunc (_u *RevisionUpdate) AddType(v migrate.RevisionType) *RevisionUpdate {\n\t_u.mutation.AddType(v)\n\treturn _u\n}\n\n// SetApplied sets the \"applied\" field.\nfunc (_u *RevisionUpdate) SetApplied(v int) *RevisionUpdate {\n\t_u.mutation.ResetApplied()\n\t_u.mutation.SetApplied(v)\n\treturn _u\n}\n\n// SetNillableApplied sets the \"applied\" field if the given value is not nil.\nfunc (_u *RevisionUpdate) SetNillableApplied(v *int) *RevisionUpdate {\n\tif v != nil {\n\t\t_u.SetApplied(*v)\n\t}\n\treturn _u\n}\n\n// AddApplied adds value to the \"applied\" field.\nfunc (_u *RevisionUpdate) AddApplied(v int) *RevisionUpdate {\n\t_u.mutation.AddApplied(v)\n\treturn _u\n}\n\n// SetTotal sets the \"total\" field.\nfunc (_u *RevisionUpdate) SetTotal(v int) *RevisionUpdate {\n\t_u.mutation.ResetTotal()\n\t_u.mutation.SetTotal(v)\n\treturn _u\n}\n\n// SetNillableTotal sets the \"total\" field if the given value is not nil.\nfunc (_u *RevisionUpdate) SetNillableTotal(v *int) *RevisionUpdate {\n\tif v != nil {\n\t\t_u.SetTotal(*v)\n\t}\n\treturn _u\n}\n\n// AddTotal adds value to the \"total\" field.\nfunc (_u *RevisionUpdate) AddTotal(v int) *RevisionUpdate {\n\t_u.mutation.AddTotal(v)\n\treturn _u\n}\n\n// SetExecutionTime sets the \"execution_time\" field.\nfunc (_u *RevisionUpdate) SetExecutionTime(v time.Duration) *RevisionUpdate {\n\t_u.mutation.ResetExecutionTime()\n\t_u.mutation.SetExecutionTime(v)\n\treturn _u\n}\n\n// SetNillableExecutionTime sets the \"execution_time\" field if the given value is not nil.\nfunc (_u *RevisionUpdate) SetNillableExecutionTime(v *time.Duration) *RevisionUpdate {\n\tif v != nil {\n\t\t_u.SetExecutionTime(*v)\n\t}\n\treturn _u\n}\n\n// AddExecutionTime adds value to the \"execution_time\" field.\nfunc (_u *RevisionUpdate) AddExecutionTime(v time.Duration) *RevisionUpdate {\n\t_u.mutation.AddExecutionTime(v)\n\treturn _u\n}\n\n// SetError sets the \"error\" field.\nfunc (_u *RevisionUpdate) SetError(v string) *RevisionUpdate {\n\t_u.mutation.SetError(v)\n\treturn _u\n}\n\n// SetNillableError sets the \"error\" field if the given value is not nil.\nfunc (_u *RevisionUpdate) SetNillableError(v *string) *RevisionUpdate {\n\tif v != nil {\n\t\t_u.SetError(*v)\n\t}\n\treturn _u\n}\n\n// ClearError clears the value of the \"error\" field.\nfunc (_u *RevisionUpdate) ClearError() *RevisionUpdate {\n\t_u.mutation.ClearError()\n\treturn _u\n}\n\n// SetErrorStmt sets the \"error_stmt\" field.\nfunc (_u *RevisionUpdate) SetErrorStmt(v string) *RevisionUpdate {\n\t_u.mutation.SetErrorStmt(v)\n\treturn _u\n}\n\n// SetNillableErrorStmt sets the \"error_stmt\" field if the given value is not nil.\nfunc (_u *RevisionUpdate) SetNillableErrorStmt(v *string) *RevisionUpdate {\n\tif v != nil {\n\t\t_u.SetErrorStmt(*v)\n\t}\n\treturn _u\n}\n\n// ClearErrorStmt clears the value of the \"error_stmt\" field.\nfunc (_u *RevisionUpdate) ClearErrorStmt() *RevisionUpdate {\n\t_u.mutation.ClearErrorStmt()\n\treturn _u\n}\n\n// SetHash sets the \"hash\" field.\nfunc (_u *RevisionUpdate) SetHash(v string) *RevisionUpdate {\n\t_u.mutation.SetHash(v)\n\treturn _u\n}\n\n// SetNillableHash sets the \"hash\" field if the given value is not nil.\nfunc (_u *RevisionUpdate) SetNillableHash(v *string) *RevisionUpdate {\n\tif v != nil {\n\t\t_u.SetHash(*v)\n\t}\n\treturn _u\n}\n\n// SetPartialHashes sets the \"partial_hashes\" field.\nfunc (_u *RevisionUpdate) SetPartialHashes(v []string) *RevisionUpdate {\n\t_u.mutation.SetPartialHashes(v)\n\treturn _u\n}\n\n// AppendPartialHashes appends value to the \"partial_hashes\" field.\nfunc (_u *RevisionUpdate) AppendPartialHashes(v []string) *RevisionUpdate {\n\t_u.mutation.AppendPartialHashes(v)\n\treturn _u\n}\n\n// ClearPartialHashes clears the value of the \"partial_hashes\" field.\nfunc (_u *RevisionUpdate) ClearPartialHashes() *RevisionUpdate {\n\t_u.mutation.ClearPartialHashes()\n\treturn _u\n}\n\n// SetOperatorVersion sets the \"operator_version\" field.\nfunc (_u *RevisionUpdate) SetOperatorVersion(v string) *RevisionUpdate {\n\t_u.mutation.SetOperatorVersion(v)\n\treturn _u\n}\n\n// SetNillableOperatorVersion sets the \"operator_version\" field if the given value is not nil.\nfunc (_u *RevisionUpdate) SetNillableOperatorVersion(v *string) *RevisionUpdate {\n\tif v != nil {\n\t\t_u.SetOperatorVersion(*v)\n\t}\n\treturn _u\n}\n\n// Mutation returns the RevisionMutation object of the builder.\nfunc (_u *RevisionUpdate) Mutation() *RevisionMutation {\n\treturn _u.mutation\n}\n\n// Save executes the query and returns the number of nodes affected by the update operation.\nfunc (_u *RevisionUpdate) Save(ctx context.Context) (int, error) {\n\treturn withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)\n}\n\n// SaveX is like Save, but panics if an error occurs.\nfunc (_u *RevisionUpdate) SaveX(ctx context.Context) int {\n\taffected, err := _u.Save(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn affected\n}\n\n// Exec executes the query.\nfunc (_u *RevisionUpdate) Exec(ctx context.Context) error {\n\t_, err := _u.Save(ctx)\n\treturn err\n}\n\n// ExecX is like Exec, but panics if an error occurs.\nfunc (_u *RevisionUpdate) ExecX(ctx context.Context) {\n\tif err := _u.Exec(ctx); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// check runs all checks and user-defined validators on the builder.\nfunc (_u *RevisionUpdate) check() error {\n\tif v, ok := _u.mutation.Applied(); ok {\n\t\tif err := revision.AppliedValidator(v); err != nil {\n\t\t\treturn &ValidationError{Name: \"applied\", err: fmt.Errorf(`ent: validator failed for field \"Revision.applied\": %w`, err)}\n\t\t}\n\t}\n\tif v, ok := _u.mutation.Total(); ok {\n\t\tif err := revision.TotalValidator(v); err != nil {\n\t\t\treturn &ValidationError{Name: \"total\", err: fmt.Errorf(`ent: validator failed for field \"Revision.total\": %w`, err)}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (_u *RevisionUpdate) sqlSave(ctx context.Context) (_node int, err error) {\n\tif err := _u.check(); err != nil {\n\t\treturn _node, err\n\t}\n\t_spec := sqlgraph.NewUpdateSpec(revision.Table, revision.Columns, sqlgraph.NewFieldSpec(revision.FieldID, field.TypeString))\n\tif ps := _u.mutation.predicates; len(ps) > 0 {\n\t\t_spec.Predicate = func(selector *sql.Selector) {\n\t\t\tfor i := range ps {\n\t\t\t\tps[i](selector)\n\t\t\t}\n\t\t}\n\t}\n\tif value, ok := _u.mutation.GetType(); ok {\n\t\t_spec.SetField(revision.FieldType, field.TypeUint, value)\n\t}\n\tif value, ok := _u.mutation.AddedType(); ok {\n\t\t_spec.AddField(revision.FieldType, field.TypeUint, value)\n\t}\n\tif value, ok := _u.mutation.Applied(); ok {\n\t\t_spec.SetField(revision.FieldApplied, field.TypeInt, value)\n\t}\n\tif value, ok := _u.mutation.AddedApplied(); ok {\n\t\t_spec.AddField(revision.FieldApplied, field.TypeInt, value)\n\t}\n\tif value, ok := _u.mutation.Total(); ok {\n\t\t_spec.SetField(revision.FieldTotal, field.TypeInt, value)\n\t}\n\tif value, ok := _u.mutation.AddedTotal(); ok {\n\t\t_spec.AddField(revision.FieldTotal, field.TypeInt, value)\n\t}\n\tif value, ok := _u.mutation.ExecutionTime(); ok {\n\t\t_spec.SetField(revision.FieldExecutionTime, field.TypeInt64, value)\n\t}\n\tif value, ok := _u.mutation.AddedExecutionTime(); ok {\n\t\t_spec.AddField(revision.FieldExecutionTime, field.TypeInt64, value)\n\t}\n\tif value, ok := _u.mutation.Error(); ok {\n\t\t_spec.SetField(revision.FieldError, field.TypeString, value)\n\t}\n\tif _u.mutation.ErrorCleared() {\n\t\t_spec.ClearField(revision.FieldError, field.TypeString)\n\t}\n\tif value, ok := _u.mutation.ErrorStmt(); ok {\n\t\t_spec.SetField(revision.FieldErrorStmt, field.TypeString, value)\n\t}\n\tif _u.mutation.ErrorStmtCleared() {\n\t\t_spec.ClearField(revision.FieldErrorStmt, field.TypeString)\n\t}\n\tif value, ok := _u.mutation.Hash(); ok {\n\t\t_spec.SetField(revision.FieldHash, field.TypeString, value)\n\t}\n\tif value, ok := _u.mutation.PartialHashes(); ok {\n\t\t_spec.SetField(revision.FieldPartialHashes, field.TypeJSON, value)\n\t}\n\tif value, ok := _u.mutation.AppendedPartialHashes(); ok {\n\t\t_spec.AddModifier(func(u *sql.UpdateBuilder) {\n\t\t\tsqljson.Append(u, revision.FieldPartialHashes, value)\n\t\t})\n\t}\n\tif _u.mutation.PartialHashesCleared() {\n\t\t_spec.ClearField(revision.FieldPartialHashes, field.TypeJSON)\n\t}\n\tif value, ok := _u.mutation.OperatorVersion(); ok {\n\t\t_spec.SetField(revision.FieldOperatorVersion, field.TypeString, value)\n\t}\n\t_spec.Node.Schema = _u.schemaConfig.Revision\n\tctx = internal.NewSchemaConfigContext(ctx, _u.schemaConfig)\n\tif _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil {\n\t\tif _, ok := err.(*sqlgraph.NotFoundError); ok {\n\t\t\terr = &NotFoundError{revision.Label}\n\t\t} else if sqlgraph.IsConstraintError(err) {\n\t\t\terr = &ConstraintError{msg: err.Error(), wrap: err}\n\t\t}\n\t\treturn 0, err\n\t}\n\t_u.mutation.done = true\n\treturn _node, nil\n}\n\n// RevisionUpdateOne is the builder for updating a single Revision entity.\ntype RevisionUpdateOne struct {\n\tconfig\n\tfields   []string\n\thooks    []Hook\n\tmutation *RevisionMutation\n}\n\n// SetType sets the \"type\" field.\nfunc (_u *RevisionUpdateOne) SetType(v migrate.RevisionType) *RevisionUpdateOne {\n\t_u.mutation.ResetType()\n\t_u.mutation.SetType(v)\n\treturn _u\n}\n\n// SetNillableType sets the \"type\" field if the given value is not nil.\nfunc (_u *RevisionUpdateOne) SetNillableType(v *migrate.RevisionType) *RevisionUpdateOne {\n\tif v != nil {\n\t\t_u.SetType(*v)\n\t}\n\treturn _u\n}\n\n// AddType adds value to the \"type\" field.\nfunc (_u *RevisionUpdateOne) AddType(v migrate.RevisionType) *RevisionUpdateOne {\n\t_u.mutation.AddType(v)\n\treturn _u\n}\n\n// SetApplied sets the \"applied\" field.\nfunc (_u *RevisionUpdateOne) SetApplied(v int) *RevisionUpdateOne {\n\t_u.mutation.ResetApplied()\n\t_u.mutation.SetApplied(v)\n\treturn _u\n}\n\n// SetNillableApplied sets the \"applied\" field if the given value is not nil.\nfunc (_u *RevisionUpdateOne) SetNillableApplied(v *int) *RevisionUpdateOne {\n\tif v != nil {\n\t\t_u.SetApplied(*v)\n\t}\n\treturn _u\n}\n\n// AddApplied adds value to the \"applied\" field.\nfunc (_u *RevisionUpdateOne) AddApplied(v int) *RevisionUpdateOne {\n\t_u.mutation.AddApplied(v)\n\treturn _u\n}\n\n// SetTotal sets the \"total\" field.\nfunc (_u *RevisionUpdateOne) SetTotal(v int) *RevisionUpdateOne {\n\t_u.mutation.ResetTotal()\n\t_u.mutation.SetTotal(v)\n\treturn _u\n}\n\n// SetNillableTotal sets the \"total\" field if the given value is not nil.\nfunc (_u *RevisionUpdateOne) SetNillableTotal(v *int) *RevisionUpdateOne {\n\tif v != nil {\n\t\t_u.SetTotal(*v)\n\t}\n\treturn _u\n}\n\n// AddTotal adds value to the \"total\" field.\nfunc (_u *RevisionUpdateOne) AddTotal(v int) *RevisionUpdateOne {\n\t_u.mutation.AddTotal(v)\n\treturn _u\n}\n\n// SetExecutionTime sets the \"execution_time\" field.\nfunc (_u *RevisionUpdateOne) SetExecutionTime(v time.Duration) *RevisionUpdateOne {\n\t_u.mutation.ResetExecutionTime()\n\t_u.mutation.SetExecutionTime(v)\n\treturn _u\n}\n\n// SetNillableExecutionTime sets the \"execution_time\" field if the given value is not nil.\nfunc (_u *RevisionUpdateOne) SetNillableExecutionTime(v *time.Duration) *RevisionUpdateOne {\n\tif v != nil {\n\t\t_u.SetExecutionTime(*v)\n\t}\n\treturn _u\n}\n\n// AddExecutionTime adds value to the \"execution_time\" field.\nfunc (_u *RevisionUpdateOne) AddExecutionTime(v time.Duration) *RevisionUpdateOne {\n\t_u.mutation.AddExecutionTime(v)\n\treturn _u\n}\n\n// SetError sets the \"error\" field.\nfunc (_u *RevisionUpdateOne) SetError(v string) *RevisionUpdateOne {\n\t_u.mutation.SetError(v)\n\treturn _u\n}\n\n// SetNillableError sets the \"error\" field if the given value is not nil.\nfunc (_u *RevisionUpdateOne) SetNillableError(v *string) *RevisionUpdateOne {\n\tif v != nil {\n\t\t_u.SetError(*v)\n\t}\n\treturn _u\n}\n\n// ClearError clears the value of the \"error\" field.\nfunc (_u *RevisionUpdateOne) ClearError() *RevisionUpdateOne {\n\t_u.mutation.ClearError()\n\treturn _u\n}\n\n// SetErrorStmt sets the \"error_stmt\" field.\nfunc (_u *RevisionUpdateOne) SetErrorStmt(v string) *RevisionUpdateOne {\n\t_u.mutation.SetErrorStmt(v)\n\treturn _u\n}\n\n// SetNillableErrorStmt sets the \"error_stmt\" field if the given value is not nil.\nfunc (_u *RevisionUpdateOne) SetNillableErrorStmt(v *string) *RevisionUpdateOne {\n\tif v != nil {\n\t\t_u.SetErrorStmt(*v)\n\t}\n\treturn _u\n}\n\n// ClearErrorStmt clears the value of the \"error_stmt\" field.\nfunc (_u *RevisionUpdateOne) ClearErrorStmt() *RevisionUpdateOne {\n\t_u.mutation.ClearErrorStmt()\n\treturn _u\n}\n\n// SetHash sets the \"hash\" field.\nfunc (_u *RevisionUpdateOne) SetHash(v string) *RevisionUpdateOne {\n\t_u.mutation.SetHash(v)\n\treturn _u\n}\n\n// SetNillableHash sets the \"hash\" field if the given value is not nil.\nfunc (_u *RevisionUpdateOne) SetNillableHash(v *string) *RevisionUpdateOne {\n\tif v != nil {\n\t\t_u.SetHash(*v)\n\t}\n\treturn _u\n}\n\n// SetPartialHashes sets the \"partial_hashes\" field.\nfunc (_u *RevisionUpdateOne) SetPartialHashes(v []string) *RevisionUpdateOne {\n\t_u.mutation.SetPartialHashes(v)\n\treturn _u\n}\n\n// AppendPartialHashes appends value to the \"partial_hashes\" field.\nfunc (_u *RevisionUpdateOne) AppendPartialHashes(v []string) *RevisionUpdateOne {\n\t_u.mutation.AppendPartialHashes(v)\n\treturn _u\n}\n\n// ClearPartialHashes clears the value of the \"partial_hashes\" field.\nfunc (_u *RevisionUpdateOne) ClearPartialHashes() *RevisionUpdateOne {\n\t_u.mutation.ClearPartialHashes()\n\treturn _u\n}\n\n// SetOperatorVersion sets the \"operator_version\" field.\nfunc (_u *RevisionUpdateOne) SetOperatorVersion(v string) *RevisionUpdateOne {\n\t_u.mutation.SetOperatorVersion(v)\n\treturn _u\n}\n\n// SetNillableOperatorVersion sets the \"operator_version\" field if the given value is not nil.\nfunc (_u *RevisionUpdateOne) SetNillableOperatorVersion(v *string) *RevisionUpdateOne {\n\tif v != nil {\n\t\t_u.SetOperatorVersion(*v)\n\t}\n\treturn _u\n}\n\n// Mutation returns the RevisionMutation object of the builder.\nfunc (_u *RevisionUpdateOne) Mutation() *RevisionMutation {\n\treturn _u.mutation\n}\n\n// Where appends a list predicates to the RevisionUpdate builder.\nfunc (_u *RevisionUpdateOne) Where(ps ...predicate.Revision) *RevisionUpdateOne {\n\t_u.mutation.Where(ps...)\n\treturn _u\n}\n\n// Select allows selecting one or more fields (columns) of the returned entity.\n// The default is selecting all fields defined in the entity schema.\nfunc (_u *RevisionUpdateOne) Select(field string, fields ...string) *RevisionUpdateOne {\n\t_u.fields = append([]string{field}, fields...)\n\treturn _u\n}\n\n// Save executes the query and returns the updated Revision entity.\nfunc (_u *RevisionUpdateOne) Save(ctx context.Context) (*Revision, error) {\n\treturn withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks)\n}\n\n// SaveX is like Save, but panics if an error occurs.\nfunc (_u *RevisionUpdateOne) SaveX(ctx context.Context) *Revision {\n\tnode, err := _u.Save(ctx)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn node\n}\n\n// Exec executes the query on the entity.\nfunc (_u *RevisionUpdateOne) Exec(ctx context.Context) error {\n\t_, err := _u.Save(ctx)\n\treturn err\n}\n\n// ExecX is like Exec, but panics if an error occurs.\nfunc (_u *RevisionUpdateOne) ExecX(ctx context.Context) {\n\tif err := _u.Exec(ctx); err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// check runs all checks and user-defined validators on the builder.\nfunc (_u *RevisionUpdateOne) check() error {\n\tif v, ok := _u.mutation.Applied(); ok {\n\t\tif err := revision.AppliedValidator(v); err != nil {\n\t\t\treturn &ValidationError{Name: \"applied\", err: fmt.Errorf(`ent: validator failed for field \"Revision.applied\": %w`, err)}\n\t\t}\n\t}\n\tif v, ok := _u.mutation.Total(); ok {\n\t\tif err := revision.TotalValidator(v); err != nil {\n\t\t\treturn &ValidationError{Name: \"total\", err: fmt.Errorf(`ent: validator failed for field \"Revision.total\": %w`, err)}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (_u *RevisionUpdateOne) sqlSave(ctx context.Context) (_node *Revision, err error) {\n\tif err := _u.check(); err != nil {\n\t\treturn _node, err\n\t}\n\t_spec := sqlgraph.NewUpdateSpec(revision.Table, revision.Columns, sqlgraph.NewFieldSpec(revision.FieldID, field.TypeString))\n\tid, ok := _u.mutation.ID()\n\tif !ok {\n\t\treturn nil, &ValidationError{Name: \"id\", err: errors.New(`ent: missing \"Revision.id\" for update`)}\n\t}\n\t_spec.Node.ID.Value = id\n\tif fields := _u.fields; len(fields) > 0 {\n\t\t_spec.Node.Columns = make([]string, 0, len(fields))\n\t\t_spec.Node.Columns = append(_spec.Node.Columns, revision.FieldID)\n\t\tfor _, f := range fields {\n\t\t\tif !revision.ValidColumn(f) {\n\t\t\t\treturn nil, &ValidationError{Name: f, err: fmt.Errorf(\"ent: invalid field %q for query\", f)}\n\t\t\t}\n\t\t\tif f != revision.FieldID {\n\t\t\t\t_spec.Node.Columns = append(_spec.Node.Columns, f)\n\t\t\t}\n\t\t}\n\t}\n\tif ps := _u.mutation.predicates; len(ps) > 0 {\n\t\t_spec.Predicate = func(selector *sql.Selector) {\n\t\t\tfor i := range ps {\n\t\t\t\tps[i](selector)\n\t\t\t}\n\t\t}\n\t}\n\tif value, ok := _u.mutation.GetType(); ok {\n\t\t_spec.SetField(revision.FieldType, field.TypeUint, value)\n\t}\n\tif value, ok := _u.mutation.AddedType(); ok {\n\t\t_spec.AddField(revision.FieldType, field.TypeUint, value)\n\t}\n\tif value, ok := _u.mutation.Applied(); ok {\n\t\t_spec.SetField(revision.FieldApplied, field.TypeInt, value)\n\t}\n\tif value, ok := _u.mutation.AddedApplied(); ok {\n\t\t_spec.AddField(revision.FieldApplied, field.TypeInt, value)\n\t}\n\tif value, ok := _u.mutation.Total(); ok {\n\t\t_spec.SetField(revision.FieldTotal, field.TypeInt, value)\n\t}\n\tif value, ok := _u.mutation.AddedTotal(); ok {\n\t\t_spec.AddField(revision.FieldTotal, field.TypeInt, value)\n\t}\n\tif value, ok := _u.mutation.ExecutionTime(); ok {\n\t\t_spec.SetField(revision.FieldExecutionTime, field.TypeInt64, value)\n\t}\n\tif value, ok := _u.mutation.AddedExecutionTime(); ok {\n\t\t_spec.AddField(revision.FieldExecutionTime, field.TypeInt64, value)\n\t}\n\tif value, ok := _u.mutation.Error(); ok {\n\t\t_spec.SetField(revision.FieldError, field.TypeString, value)\n\t}\n\tif _u.mutation.ErrorCleared() {\n\t\t_spec.ClearField(revision.FieldError, field.TypeString)\n\t}\n\tif value, ok := _u.mutation.ErrorStmt(); ok {\n\t\t_spec.SetField(revision.FieldErrorStmt, field.TypeString, value)\n\t}\n\tif _u.mutation.ErrorStmtCleared() {\n\t\t_spec.ClearField(revision.FieldErrorStmt, field.TypeString)\n\t}\n\tif value, ok := _u.mutation.Hash(); ok {\n\t\t_spec.SetField(revision.FieldHash, field.TypeString, value)\n\t}\n\tif value, ok := _u.mutation.PartialHashes(); ok {\n\t\t_spec.SetField(revision.FieldPartialHashes, field.TypeJSON, value)\n\t}\n\tif value, ok := _u.mutation.AppendedPartialHashes(); ok {\n\t\t_spec.AddModifier(func(u *sql.UpdateBuilder) {\n\t\t\tsqljson.Append(u, revision.FieldPartialHashes, value)\n\t\t})\n\t}\n\tif _u.mutation.PartialHashesCleared() {\n\t\t_spec.ClearField(revision.FieldPartialHashes, field.TypeJSON)\n\t}\n\tif value, ok := _u.mutation.OperatorVersion(); ok {\n\t\t_spec.SetField(revision.FieldOperatorVersion, field.TypeString, value)\n\t}\n\t_spec.Node.Schema = _u.schemaConfig.Revision\n\tctx = internal.NewSchemaConfigContext(ctx, _u.schemaConfig)\n\t_node = &Revision{config: _u.config}\n\t_spec.Assign = _node.assignValues\n\t_spec.ScanValues = _node.scanValues\n\tif err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil {\n\t\tif _, ok := err.(*sqlgraph.NotFoundError); ok {\n\t\t\terr = &NotFoundError{revision.Label}\n\t\t} else if sqlgraph.IsConstraintError(err) {\n\t\t\terr = &ConstraintError{msg: err.Error(), wrap: err}\n\t\t}\n\t\treturn nil, err\n\t}\n\t_u.mutation.done = true\n\treturn _node, nil\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/runtime/runtime.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage runtime\n\n// The schema-stitching logic is generated in ariga.io/atlas/cmd/atlas/internal/migrate/ent/runtime.go\n\nconst (\n\tVersion = \"v0.14.5-0.20250523082027-21ecfa0872d4\"           // Version of ent codegen.\n\tSum     = \"h1:d7UZAvQCnOp1PyiHAWkPCXBEPW3tVjraiK/RZlsW0XY=\" // Sum of ent codegen.\n)\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/runtime.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport (\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/schema\"\n\t\"ariga.io/atlas/sql/migrate\"\n)\n\n// The init function reads all schema descriptors with runtime code\n// (default values, validators, hooks and policies) and stitches it\n// to their package variables.\nfunc init() {\n\trevisionFields := schema.Revision{}.Fields()\n\t_ = revisionFields\n\t// revisionDescType is the schema descriptor for type field.\n\trevisionDescType := revisionFields[2].Descriptor()\n\t// revision.DefaultType holds the default value on creation for the type field.\n\trevision.DefaultType = migrate.RevisionType(revisionDescType.Default.(uint))\n\t// revisionDescApplied is the schema descriptor for applied field.\n\trevisionDescApplied := revisionFields[3].Descriptor()\n\t// revision.DefaultApplied holds the default value on creation for the applied field.\n\trevision.DefaultApplied = revisionDescApplied.Default.(int)\n\t// revision.AppliedValidator is a validator for the \"applied\" field. It is called by the builders before save.\n\trevision.AppliedValidator = revisionDescApplied.Validators[0].(func(int) error)\n\t// revisionDescTotal is the schema descriptor for total field.\n\trevisionDescTotal := revisionFields[4].Descriptor()\n\t// revision.DefaultTotal holds the default value on creation for the total field.\n\trevision.DefaultTotal = revisionDescTotal.Default.(int)\n\t// revision.TotalValidator is a validator for the \"total\" field. It is called by the builders before save.\n\trevision.TotalValidator = revisionDescTotal.Validators[0].(func(int) error)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/schema/revision.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schema\n\nimport (\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\n\t\"entgo.io/ent\"\n\t\"entgo.io/ent/dialect/entsql\"\n\t\"entgo.io/ent/schema\"\n\t\"entgo.io/ent/schema/field\"\n)\n\n// DefaultRevisionSchema is the default schema for storing revisions table.\nconst DefaultRevisionSchema = \"atlas_schema_revisions\"\n\n// Revision holds the schema definition for the Revision entity.\ntype Revision struct {\n\tent.Schema\n}\n\n// Fields of the Revision.\nfunc (Revision) Fields() []ent.Field {\n\treturn []ent.Field{\n\t\tfield.String(\"id\").\n\t\t\tStorageKey(\"version\").\n\t\t\tImmutable(),\n\t\tfield.String(\"description\").\n\t\t\tImmutable(),\n\t\tfield.Uint(\"type\").\n\t\t\tGoType(migrate.RevisionType(0)).\n\t\t\tDefault(uint(migrate.RevisionTypeExecute)),\n\t\tfield.Int(\"applied\").\n\t\t\tNonNegative().\n\t\t\tDefault(0),\n\t\tfield.Int(\"total\").\n\t\t\tNonNegative().\n\t\t\tDefault(0),\n\t\tfield.Time(\"executed_at\").\n\t\t\tImmutable(),\n\t\tfield.Int64(\"execution_time\").\n\t\t\tGoType(time.Duration(0)),\n\t\tfield.Text(\"error\").\n\t\t\tOptional(),\n\t\tfield.Text(\"error_stmt\").\n\t\t\tOptional(),\n\t\tfield.String(\"hash\"),\n\t\tfield.Strings(\"partial_hashes\").\n\t\t\tOptional(),\n\t\tfield.String(\"operator_version\"),\n\t}\n}\n\n// Annotations of the Revision.\nfunc (Revision) Annotations() []schema.Annotation {\n\treturn []schema.Annotation{\n\t\tentsql.Annotation{Table: DefaultRevisionSchema},\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/template/convert.tmpl",
    "content": "{{/* gotype: entgo.io/ent/entc/gen.Graph */}}\n\n{{ define \"convert\" }}\n\n{{ $pkg := base $.Config.Package }}\n{{ template \"header\" $ }}\n\nimport \"ariga.io/atlas/sql/migrate\"\n\n{{ range $n := $.Nodes }}\n    {{ if eq $n.Name \"Revision\" }}\n        {{ $builder := $n.CreateName }}\n        {{ $receiver := receiver $builder }}\n\n        // SetRevision takes the values for each field from the given migrate.Revision.\n        func ({{ $receiver }} *{{ $builder }}) SetRevision(rev *migrate.Revision) *{{ $builder }} {\n            {{ $receiver }}.SetID(rev.Version)\n            {{- range $f := $n.Fields }}\n                {{ $receiver }}.Set{{ $f.StructField }}(rev.{{ $f.StructField }})\n            {{- end }}\n            return {{ $receiver }}\n        }\n\n        // AtlasRevision returns an migrate.Revision from the current Revision.\n        func({{ $n.Receiver }} *Revision) AtlasRevision() *migrate.Revision {\n            return &migrate.Revision{\n                Version: {{ $n.Receiver }}.ID,\n                {{- range $f := $n.Fields }}\n                    {{ $f.StructField }}: {{ $n.Receiver }}.{{ $f.StructField }},\n                {{- end }}\n            }\n        }\n    {{ end }}\n{{ end }}\n\n{{ end }}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/ent/tx.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Code generated by entc, DO NOT EDIT.\n\npackage ent\n\nimport (\n\t\"context\"\n\tstdsql \"database/sql\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"entgo.io/ent/dialect\"\n)\n\n// Tx is a transactional client that is created by calling Client.Tx().\ntype Tx struct {\n\tconfig\n\t// Revision is the client for interacting with the Revision builders.\n\tRevision *RevisionClient\n\n\t// lazily loaded.\n\tclient     *Client\n\tclientOnce sync.Once\n\t// ctx lives for the life of the transaction. It is\n\t// the same context used by the underlying connection.\n\tctx context.Context\n}\n\ntype (\n\t// Committer is the interface that wraps the Commit method.\n\tCommitter interface {\n\t\tCommit(context.Context, *Tx) error\n\t}\n\n\t// The CommitFunc type is an adapter to allow the use of ordinary\n\t// function as a Committer. If f is a function with the appropriate\n\t// signature, CommitFunc(f) is a Committer that calls f.\n\tCommitFunc func(context.Context, *Tx) error\n\n\t// CommitHook defines the \"commit middleware\". A function that gets a Committer\n\t// and returns a Committer. For example:\n\t//\n\t//\thook := func(next ent.Committer) ent.Committer {\n\t//\t\treturn ent.CommitFunc(func(ctx context.Context, tx *ent.Tx) error {\n\t//\t\t\t// Do some stuff before.\n\t//\t\t\tif err := next.Commit(ctx, tx); err != nil {\n\t//\t\t\t\treturn err\n\t//\t\t\t}\n\t//\t\t\t// Do some stuff after.\n\t//\t\t\treturn nil\n\t//\t\t})\n\t//\t}\n\t//\n\tCommitHook func(Committer) Committer\n)\n\n// Commit calls f(ctx, m).\nfunc (f CommitFunc) Commit(ctx context.Context, tx *Tx) error {\n\treturn f(ctx, tx)\n}\n\n// Commit commits the transaction.\nfunc (tx *Tx) Commit() error {\n\ttxDriver := tx.config.driver.(*txDriver)\n\tvar fn Committer = CommitFunc(func(context.Context, *Tx) error {\n\t\treturn txDriver.tx.Commit()\n\t})\n\ttxDriver.mu.Lock()\n\thooks := append([]CommitHook(nil), txDriver.onCommit...)\n\ttxDriver.mu.Unlock()\n\tfor i := len(hooks) - 1; i >= 0; i-- {\n\t\tfn = hooks[i](fn)\n\t}\n\treturn fn.Commit(tx.ctx, tx)\n}\n\n// OnCommit adds a hook to call on commit.\nfunc (tx *Tx) OnCommit(f CommitHook) {\n\ttxDriver := tx.config.driver.(*txDriver)\n\ttxDriver.mu.Lock()\n\ttxDriver.onCommit = append(txDriver.onCommit, f)\n\ttxDriver.mu.Unlock()\n}\n\ntype (\n\t// Rollbacker is the interface that wraps the Rollback method.\n\tRollbacker interface {\n\t\tRollback(context.Context, *Tx) error\n\t}\n\n\t// The RollbackFunc type is an adapter to allow the use of ordinary\n\t// function as a Rollbacker. If f is a function with the appropriate\n\t// signature, RollbackFunc(f) is a Rollbacker that calls f.\n\tRollbackFunc func(context.Context, *Tx) error\n\n\t// RollbackHook defines the \"rollback middleware\". A function that gets a Rollbacker\n\t// and returns a Rollbacker. For example:\n\t//\n\t//\thook := func(next ent.Rollbacker) ent.Rollbacker {\n\t//\t\treturn ent.RollbackFunc(func(ctx context.Context, tx *ent.Tx) error {\n\t//\t\t\t// Do some stuff before.\n\t//\t\t\tif err := next.Rollback(ctx, tx); err != nil {\n\t//\t\t\t\treturn err\n\t//\t\t\t}\n\t//\t\t\t// Do some stuff after.\n\t//\t\t\treturn nil\n\t//\t\t})\n\t//\t}\n\t//\n\tRollbackHook func(Rollbacker) Rollbacker\n)\n\n// Rollback calls f(ctx, m).\nfunc (f RollbackFunc) Rollback(ctx context.Context, tx *Tx) error {\n\treturn f(ctx, tx)\n}\n\n// Rollback rollbacks the transaction.\nfunc (tx *Tx) Rollback() error {\n\ttxDriver := tx.config.driver.(*txDriver)\n\tvar fn Rollbacker = RollbackFunc(func(context.Context, *Tx) error {\n\t\treturn txDriver.tx.Rollback()\n\t})\n\ttxDriver.mu.Lock()\n\thooks := append([]RollbackHook(nil), txDriver.onRollback...)\n\ttxDriver.mu.Unlock()\n\tfor i := len(hooks) - 1; i >= 0; i-- {\n\t\tfn = hooks[i](fn)\n\t}\n\treturn fn.Rollback(tx.ctx, tx)\n}\n\n// OnRollback adds a hook to call on rollback.\nfunc (tx *Tx) OnRollback(f RollbackHook) {\n\ttxDriver := tx.config.driver.(*txDriver)\n\ttxDriver.mu.Lock()\n\ttxDriver.onRollback = append(txDriver.onRollback, f)\n\ttxDriver.mu.Unlock()\n}\n\n// Client returns a Client that binds to current transaction.\nfunc (tx *Tx) Client() *Client {\n\ttx.clientOnce.Do(func() {\n\t\ttx.client = &Client{config: tx.config}\n\t\ttx.client.init()\n\t})\n\treturn tx.client\n}\n\nfunc (tx *Tx) init() {\n\ttx.Revision = NewRevisionClient(tx.config)\n}\n\n// txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation.\n// The idea is to support transactions without adding any extra code to the builders.\n// When a builder calls to driver.Tx(), it gets the same dialect.Tx instance.\n// Commit and Rollback are nop for the internal builders and the user must call one\n// of them in order to commit or rollback the transaction.\n//\n// If a closed transaction is embedded in one of the generated entities, and the entity\n// applies a query, for example: Revision.QueryXXX(), the query will be executed\n// through the driver which created this transaction.\n//\n// Note that txDriver is not goroutine safe.\ntype txDriver struct {\n\t// the driver we started the transaction from.\n\tdrv dialect.Driver\n\t// tx is the underlying transaction.\n\ttx dialect.Tx\n\t// completion hooks.\n\tmu         sync.Mutex\n\tonCommit   []CommitHook\n\tonRollback []RollbackHook\n}\n\n// newTx creates a new transactional driver.\nfunc newTx(ctx context.Context, drv dialect.Driver) (*txDriver, error) {\n\ttx, err := drv.Tx(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &txDriver{tx: tx, drv: drv}, nil\n}\n\n// Tx returns the transaction wrapper (txDriver) to avoid Commit or Rollback calls\n// from the internal builders. Should be called only by the internal builders.\nfunc (tx *txDriver) Tx(context.Context) (dialect.Tx, error) { return tx, nil }\n\n// Dialect returns the dialect of the driver we started the transaction from.\nfunc (tx *txDriver) Dialect() string { return tx.drv.Dialect() }\n\n// Close is a nop close.\nfunc (*txDriver) Close() error { return nil }\n\n// Commit is a nop commit for the internal builders.\n// User must call `Tx.Commit` in order to commit the transaction.\nfunc (*txDriver) Commit() error { return nil }\n\n// Rollback is a nop rollback for the internal builders.\n// User must call `Tx.Rollback` in order to rollback the transaction.\nfunc (*txDriver) Rollback() error { return nil }\n\n// Exec calls tx.Exec.\nfunc (tx *txDriver) Exec(ctx context.Context, query string, args, v any) error {\n\treturn tx.tx.Exec(ctx, query, args, v)\n}\n\n// Query calls tx.Query.\nfunc (tx *txDriver) Query(ctx context.Context, query string, args, v any) error {\n\treturn tx.tx.Query(ctx, query, args, v)\n}\n\nvar _ dialect.Driver = (*txDriver)(nil)\n\n// ExecContext allows calling the underlying ExecContext method of the transaction if it is supported by it.\n// See, database/sql#Tx.ExecContext for more information.\nfunc (tx *txDriver) ExecContext(ctx context.Context, query string, args ...any) (stdsql.Result, error) {\n\tex, ok := tx.tx.(interface {\n\t\tExecContext(context.Context, string, ...any) (stdsql.Result, error)\n\t})\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"Tx.ExecContext is not supported\")\n\t}\n\treturn ex.ExecContext(ctx, query, args...)\n}\n\n// QueryContext allows calling the underlying QueryContext method of the transaction if it is supported by it.\n// See, database/sql#Tx.QueryContext for more information.\nfunc (tx *txDriver) QueryContext(ctx context.Context, query string, args ...any) (*stdsql.Rows, error) {\n\tq, ok := tx.tx.(interface {\n\t\tQueryContext(context.Context, string, ...any) (*stdsql.Rows, error)\n\t})\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"Tx.QueryContext is not supported\")\n\t}\n\treturn q.QueryContext(ctx, query, args...)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/migrate.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage migrate\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"net/url\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent\"\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/mysql\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t\"ariga.io/atlas/sql/sqlite\"\n\t\"ariga.io/atlas/sql/sqltool\"\n\n\t\"entgo.io/ent/dialect\"\n\t\"entgo.io/ent/dialect/sql\"\n\tentschema \"entgo.io/ent/dialect/sql/schema\"\n\t\"github.com/google/uuid\"\n)\n\ntype (\n\t// RevisionReadWriter is a revision read-writer with migration capabilities.\n\tRevisionReadWriter interface {\n\t\tmigrate.RevisionReadWriter\n\t\t// CurrentRevision returns the current revision in the revisions table.\n\t\tCurrentRevision(context.Context) (*migrate.Revision, error)\n\t\t// Migrate applies the migration of the revisions table.\n\t\tMigrate(context.Context) error\n\t\t// ID returns the current target identifier.\n\t\tID(context.Context, string) (string, error)\n\t}\n\t// EntRevisions provides implementation for the migrate.RevisionReadWriter interface.\n\tEntRevisions struct {\n\t\tac     *sqlclient.Client // underlying Atlas client\n\t\tec     *ent.Client       // underlying Ent client\n\t\tschema string            // name of the schema the revision table resides in\n\t}\n\n\t// Option allows to configure EntRevisions by using functional arguments.\n\tOption func(*EntRevisions) error\n)\n\n// Dialect returns the \"ent dialect\" of the Ent client.\nfunc (r *EntRevisions) Dialect() string {\n\treturn EntDialect(r.ac.Name)\n}\n\n// EntDialect returns the Ent dialect for the given driver.\nfunc EntDialect(d string) string {\n\tswitch {\n\tcase d == mysql.DriverMaria:\n\t\treturn dialect.MySQL // Ent does not support \"mariadb\" as dialect.\n\tcase strings.HasPrefix(d, \"libsql\"):\n\t\treturn dialect.SQLite // Ent does not support \"libsql\" as dialect.\n\tcase d == sqlite.DriverName:\n\t\treturn dialect.SQLite // Ent does not support \"sqlite\" as dialect.\n\tdefault:\n\t\treturn d\n\t}\n}\n\n// RevisionsForClient creates a new RevisionReadWriter for the given sqlclient.Client.\nfunc RevisionsForClient(ctx context.Context, ac *sqlclient.Client, schema string) (RevisionReadWriter, error) {\n\t// If the driver supports the RevisionReadWriter interface, use it.\n\tif drv, ok := ac.Driver.(interface {\n\t\tRevisionsReadWriter(context.Context, string) (migrate.RevisionReadWriter, error)\n\t}); ok {\n\t\trrw, err := drv.RevisionsReadWriter(ctx, schema)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif rrw, ok := rrw.(RevisionReadWriter); ok {\n\t\t\treturn rrw, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"unexpected revision read-writer type: %T\", rrw)\n\t}\n\treturn NewEntRevisions(ctx, ac, WithSchema(schema))\n}\n\n// NewEntRevisions creates a new EntRevisions with the given sqlclient.Client.\nfunc NewEntRevisions(ctx context.Context, ac *sqlclient.Client, opts ...Option) (*EntRevisions, error) {\n\tr := &EntRevisions{ac: ac}\n\tfor _, opt := range opts {\n\t\tif err := opt(r); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif r.Dialect() == dialect.SQLite && r.schema != \"\" && r.schema != \"main\" {\n\t\treturn nil, fmt.Errorf(\"cannot store revisions-table in a separate schema (%q) with SQLite driver\", r.schema)\n\t}\n\t// Create the connection with the underlying migrate.Driver to have it inside a possible transaction.\n\tentopts := []ent.Option{ent.Driver(sql.NewDriver(r.Dialect(), sql.Conn{ExecQuerier: r.ac.Driver}))}\n\t// SQLite does not support multiple schema, therefore schema-config is only needed for other dialects.\n\tif r.Dialect() != dialect.SQLite {\n\t\t// Make sure the schema to store the revisions table in does exist.\n\t\t_, err := r.ac.InspectSchema(ctx, r.schema, &schema.InspectOptions{Mode: schema.InspectSchemas})\n\t\tif err != nil && !schema.IsNotExistError(err) {\n\t\t\treturn nil, err\n\t\t}\n\t\tif schema.IsNotExistError(err) {\n\t\t\tif err := r.ac.ApplyChanges(ctx, []schema.Change{\n\t\t\t\t&schema.AddSchema{S: &schema.Schema{Name: r.schema}},\n\t\t\t}); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\t// Tell Ent to operate on a given schema.\n\t\tif r.schema != \"\" {\n\t\t\tentopts = append(entopts, ent.AlternateSchema(ent.SchemaConfig{Revision: r.schema}))\n\t\t}\n\t}\n\t// Instantiate the Ent client and migrate the revision schema.\n\tr.ec = ent.NewClient(entopts...)\n\treturn r, nil\n}\n\n// WithSchema configures the schema to use for the revision table.\nfunc WithSchema(s string) Option {\n\treturn func(r *EntRevisions) error {\n\t\tr.schema = s\n\t\treturn nil\n\t}\n}\n\n// Ident returns the table identifier.\nfunc (r *EntRevisions) Ident() *migrate.TableIdent {\n\treturn &migrate.TableIdent{Name: revision.Table, Schema: r.schema}\n}\n\n// ReadRevision reads a revision from the revisions table.\n//\n// ReadRevision will not return results only saved in cache.\nfunc (r *EntRevisions) ReadRevision(ctx context.Context, v string) (*migrate.Revision, error) {\n\tif v == revisionID {\n\t\treturn nil, errors.New(\"cannot read revision-table identifier as revision\")\n\t}\n\trev, err := r.ec.Revision.Get(ctx, v)\n\tif err != nil && !ent.IsNotFound(err) {\n\t\treturn nil, err\n\t}\n\tif ent.IsNotFound(err) {\n\t\treturn nil, migrate.ErrRevisionNotExist\n\t}\n\treturn rev.AtlasRevision(), nil\n}\n\n// ReadRevisions reads the revisions from the revisions table.\n//\n// ReadRevisions will not return results only saved to cache.\nfunc (r *EntRevisions) ReadRevisions(ctx context.Context) ([]*migrate.Revision, error) {\n\trevs, err := r.ec.Revision.Query().\n\t\tWhere(revision.IDNEQ(revisionID)).\n\t\tOrder(revision.ByID()).\n\t\tAll(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tret := make([]*migrate.Revision, len(revs))\n\tfor i, rev := range revs {\n\t\tret[i] = rev.AtlasRevision()\n\t}\n\treturn ret, nil\n}\n\n// CurrentRevision returns the current (latest) revision in the revisions table.\nfunc (r *EntRevisions) CurrentRevision(ctx context.Context) (*migrate.Revision, error) {\n\trev, err := r.ec.Revision.Query().\n\t\tWhere(revision.IDNEQ(revisionID)).\n\t\tOrder(revision.ByID(sql.OrderDesc())).\n\t\tFirst(ctx)\n\tif err != nil && !ent.IsNotFound(err) {\n\t\treturn nil, err\n\t}\n\tif ent.IsNotFound(err) {\n\t\treturn nil, migrate.ErrRevisionNotExist\n\t}\n\treturn rev.AtlasRevision(), nil\n}\n\n// WriteRevision writes a revision to the revisions table.\nfunc (r *EntRevisions) WriteRevision(ctx context.Context, rev *migrate.Revision) error {\n\tif rev.Version == revisionID {\n\t\treturn errors.New(\"writing the revision-table identifier is not allowed\")\n\t}\n\treturn r.ec.Revision.Create().\n\t\tSetRevision(rev).\n\t\tOnConflict(sql.ConflictColumns(revision.FieldID)).\n\t\tUpdateNewValues().\n\t\tExec(ctx)\n}\n\n// DeleteRevision deletes a revision from the revisions table.\nfunc (r *EntRevisions) DeleteRevision(ctx context.Context, v string) error {\n\tif v == revisionID {\n\t\treturn errors.New(\"deleting the revision-table identifier is not allowed\")\n\t}\n\treturn r.ec.Revision.DeleteOneID(v).Exec(ctx)\n}\n\n// Migrate attempts to create / update the revisions table. This is separated since Ent attempts to wrap the migration\n// execution in a transaction and assumes the underlying connection is of type *sql.DB, which is not true for actually\n// reading and writing revisions.\nfunc (r *EntRevisions) Migrate(ctx context.Context) (err error) {\n\tvar (\n\t\topts = []entschema.MigrateOption{\n\t\t\tentschema.WithDropColumn(true),\n\t\t}\n\t\tc = ent.NewClient(ent.Driver(sql.OpenDB(r.Dialect(), r.ac.DB)))\n\t)\n\tswitch {\n\tcase r.Dialect() != dialect.SQLite:\n\t\t// Ensure the ent client is bound to the requested revision schema. Open a new connection, if not.\n\t\tif r.ac.URL.Schema != r.schema {\n\t\t\tsc, err := sqlclient.OpenURL(ctx, r.ac.URL.URL, sqlclient.OpenSchema(r.schema))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer sc.Close()\n\t\t\tc = ent.NewClient(ent.Driver(sql.OpenDB(r.Dialect(), sc.DB)))\n\t\t}\n\t\t// In non-SQLite databases, there can be multiple schemas, and we\n\t\t// prefer to pass it explicitly rather than calling to CURRENT_SCHEMA().\n\t\topts = append(opts, entschema.WithSchemaName(r.schema))\n\tdefault: // SQLite.\n\t\tvar on sql.NullBool\n\t\tif err := r.ac.DB.QueryRowContext(ctx, \"PRAGMA foreign_keys\").Scan(&on); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !on.Bool {\n\t\t\t// Ent requires the foreign key checks in SQLite to be enabled for migration. Since Atlas does not,\n\t\t\t// ensure they are set for the migration attempt and restore previous setting afterwards.\n\t\t\t_, err := r.ac.ExecContext(ctx, \"PRAGMA foreign_keys = on\")\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_, err2 := r.ac.ExecContext(ctx, \"PRAGMA foreign_keys = off\")\n\t\t\t\tif err2 != nil {\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\terr = fmt.Errorf(\"%v: %w\", err2, err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\terr = err2\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}\n\treturn c.Schema.Create(ctx, append(opts, entschema.WithDiffHook(func(next entschema.Differ) entschema.Differ {\n\t\treturn entschema.DiffFunc(func(current, desired *schema.Schema) ([]schema.Change, error) {\n\t\t\tchanges, err := next.Diff(current, desired)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\t// Skip all changes beside revisions\n\t\t\t// table creation or modification.\n\t\t\tfor i := range changes {\n\t\t\t\tswitch cs := changes[i].(type) {\n\t\t\t\tcase *schema.AddTable:\n\t\t\t\t\tr.maySetSchemaQualifier(cs.T)\n\t\t\t\t\tif cs.T.Name == revision.Table {\n\t\t\t\t\t\treturn schema.Changes{cs}, nil\n\t\t\t\t\t}\n\t\t\t\tcase *schema.ModifyTable:\n\t\t\t\t\tr.maySetSchemaQualifier(cs.T)\n\t\t\t\t\tif cs.T.Name == revision.Table {\n\t\t\t\t\t\treturn schema.Changes{cs}, nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil, nil\n\t\t})\n\t}))...)\n}\n\n// maySetSchemaQualifier sets the schema on the atlas_schema_revisions table\n// for cases the migration should use qualified identifiers due to some limitation\n// in PostgreSQL services that use \"connection pooler\" and do not support the \"search_path\"\n// parameter. See: https://github.com/ariga/atlas/issues/2509.\nfunc (r *EntRevisions) maySetSchemaQualifier(t *schema.Table) {\n\tif r.Dialect() != dialect.Postgres || r.schema == \"\" || t.Schema != nil {\n\t\treturn // Not PG, or schema-scope (e.g., public).\n\t}\n\tif knownServices := []string{\"neon.tech\", \"supabase.co\", \"supabase.com\"}; slices.ContainsFunc(knownServices, func(s string) bool {\n\t\treturn strings.HasSuffix(r.ac.URL.Host, s)\n\t}) {\n\t\tt.SetSchema(schema.New(r.schema))\n\t}\n}\n\n// revisionID holds the column \"id\" (\"version\") of the revision that holds the identifier of the\n// connected revisions table. The \".\" prefix ensures the is it lower than any other revisions.\nconst revisionID = \".atlas_cloud_identifier\"\n\n// ID returns the identifier of the connected revisions table.\nfunc (r *EntRevisions) ID(ctx context.Context, operatorV string) (string, error) {\n\terr := r.ec.Revision.Create().\n\t\tSetID(revisionID).                // identifier key\n\t\tSetDescription(uuid.NewString()). // actual revision identifier\n\t\tSetOperatorVersion(operatorV).    // operator version\n\t\tSetExecutedAt(time.Now()).        // when it was set\n\t\tSetExecutionTime(0).              // dummy values\n\t\tSetHash(\"\").\n\t\tOnConflict(sql.ConflictColumns(revision.FieldID)).\n\t\tIgnore().\n\t\tExec(ctx)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"upsert revision-table id: %w\", err)\n\t}\n\trev, err := r.ec.Revision.Get(ctx, revisionID)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"read revision-table id: %w\", err)\n\t}\n\tid, err := uuid.Parse(rev.Description)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"parse revision-table id: %w\", err)\n\t}\n\treturn id.String(), nil\n}\n\nvar _ migrate.RevisionReadWriter = (*EntRevisions)(nil)\n\n// List of supported formats.\nconst (\n\tFormatAtlas         = \"atlas\"\n\tFormatGolangMigrate = \"golang-migrate\"\n\tFormatGoose         = \"goose\"\n\tFormatFlyway        = \"flyway\"\n\tFormatLiquibase     = \"liquibase\"\n\tFormatDBMate        = \"dbmate\"\n)\n\n// Formats is the list of supported formats.\nvar Formats = []string{FormatAtlas, FormatGolangMigrate, FormatGoose, FormatFlyway, FormatLiquibase, FormatDBMate}\n\n// Formatter returns the dir formatter for its URL.\nfunc Formatter(u *url.URL) (migrate.Formatter, error) {\n\tswitch f := u.Query().Get(\"format\"); f {\n\tcase \"\", FormatAtlas:\n\t\treturn migrate.DefaultFormatter, nil\n\tcase FormatGolangMigrate:\n\t\treturn sqltool.GolangMigrateFormatter, nil\n\tcase FormatGoose:\n\t\treturn sqltool.GooseFormatter, nil\n\tcase FormatFlyway:\n\t\treturn sqltool.FlywayFormatter, nil\n\tcase FormatLiquibase:\n\t\treturn sqltool.LiquibaseFormatter, nil\n\tcase FormatDBMate:\n\t\treturn sqltool.DBMateFormatter, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown format %q\", f)\n\t}\n}\n\n// Dir parses u and calls dirURL.\nfunc Dir(ctx context.Context, u string, create bool) (migrate.Dir, error) {\n\tparsed, err := url.Parse(u)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn DirURL(ctx, parsed, create)\n}\n\n// Directory types (URL schemes).\nconst (\n\tDirTypeMem   = \"mem\"\n\tDirTypeFile  = \"file\"\n\tDirTypeAtlas = \"atlas\"\n)\n\n// DefaultDirName is the default directory name.\nconst DefaultDirName = \"migrations\"\n\n// DirURL returns a migrate.Dir to use as migration directory.\nfunc DirURL(ctx context.Context, u *url.URL, create bool) (migrate.Dir, error) {\n\tp := filepath.Join(u.Host, u.Path)\n\tswitch u.Scheme {\n\tcase DirTypeMem:\n\t\treturn migrate.OpenMemDir(path.Join(u.Host, u.Path)), nil\n\tcase DirTypeFile:\n\t\tif p == \"\" {\n\t\t\tp = DefaultDirName\n\t\t}\n\tcase DirTypeAtlas:\n\t\treturn openAtlasDir(ctx, u)\n\tcase \"\":\n\t\treturn nil, fmt.Errorf(\"missing scheme for dir url. Did you mean %q? \", fmt.Sprintf(\"%s://%s\", DirTypeFile, u.Path))\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported driver %q\", u.Scheme)\n\t}\n\tfn := func() (migrate.Dir, error) { return migrate.NewLocalDir(p) }\n\tswitch f := u.Query().Get(\"format\"); f {\n\tcase \"\", FormatAtlas:\n\t\t// this is the default\n\tcase FormatGolangMigrate:\n\t\tfn = func() (migrate.Dir, error) { return sqltool.NewGolangMigrateDir(p) }\n\tcase FormatGoose:\n\t\tfn = func() (migrate.Dir, error) { return sqltool.NewGooseDir(p) }\n\tcase FormatFlyway:\n\t\tfn = func() (migrate.Dir, error) { return sqltool.NewFlywayDir(p) }\n\tcase FormatLiquibase:\n\t\tfn = func() (migrate.Dir, error) { return sqltool.NewLiquibaseDir(p) }\n\tcase FormatDBMate:\n\t\tfn = func() (migrate.Dir, error) { return sqltool.NewDBMateDir(p) }\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown dir format %q\", f)\n\t}\n\td, err := fn()\n\tif create && errors.Is(err, fs.ErrNotExist) {\n\t\tif err := os.MkdirAll(p, 0755); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\td, err = fn()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn d, err\n}\n\n// ChangesToRealm returns the schema changes for creating the given Realm.\nfunc ChangesToRealm(c *sqlclient.Client, r *schema.Realm) schema.Changes {\n\tvar changes schema.Changes\n\tfor _, o := range r.Objects {\n\t\tchanges = append(changes, &schema.AddObject{O: o})\n\t}\n\tfor _, s := range r.Schemas {\n\t\t// Generate commands for creating the schemas on realm-mode.\n\t\tif c.URL.Schema == \"\" {\n\t\t\tchanges = append(changes, &schema.AddSchema{S: s})\n\t\t}\n\t\tfor _, o := range s.Objects {\n\t\t\tchanges = append(changes, &schema.AddObject{O: o})\n\t\t}\n\t\tfor _, t := range s.Tables {\n\t\t\tchanges = append(changes, &schema.AddTable{T: t})\n\t\t\tfor _, r := range t.Triggers {\n\t\t\t\tchanges = append(changes, &schema.AddTrigger{T: r})\n\t\t\t}\n\t\t}\n\t\tfor _, v := range s.Views {\n\t\t\tchanges = append(changes, &schema.AddView{V: v})\n\t\t\tfor _, r := range v.Triggers {\n\t\t\t\tchanges = append(changes, &schema.AddTrigger{T: r})\n\t\t\t}\n\t\t}\n\t\tfor _, f := range s.Funcs {\n\t\t\tchanges = append(changes, &schema.AddFunc{F: f})\n\t\t}\n\t\tfor _, p := range s.Procs {\n\t\t\tchanges = append(changes, &schema.AddProc{P: p})\n\t\t}\n\t}\n\treturn changes\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/migrate_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage migrate\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n)\n\nfunc openAtlasDir(context.Context, *url.URL) (migrate.Dir, error) {\n\treturn nil, fmt.Errorf(\"atlas remote directory is not supported by this release. See: https://atlasgo.io/getting-started\")\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/migrate_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage migrate\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migrate/ent/revision\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t\"ariga.io/atlas/sql/sqltool\"\n\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFormatter(t *testing.T) {\n\tu, err := url.Parse(\"file://migrations\")\n\trequire.NoError(t, err)\n\tf, err := Formatter(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, migrate.DefaultFormatter, f)\n\n\tu, err = url.Parse(\"file://migrations?format=atlas\")\n\trequire.NoError(t, err)\n\tf, err = Formatter(u)\n\n\tu, err = url.Parse(\"file://migrations?format=flyway\")\n\trequire.NoError(t, err)\n\tf, err = Formatter(u)\n\trequire.NoError(t, err)\n\trequire.Equal(t, sqltool.FlywayFormatter, f)\n}\n\nfunc TestRevisionsForClient(t *testing.T) {\n\tctx := context.Background()\n\tc, err := sqlclient.Open(ctx, \"sqlite://?mode=memory\")\n\trequire.NoError(t, err)\n\tvar rrw RevisionReadWriter\n\n\trrw, err = RevisionsForClient(ctx, c, \"\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, rrw)\n\t_, ok := rrw.(*EntRevisions)\n\trequire.True(t, ok, \"RevisionsForClient should return an EntRevisions\")\n\n\tdrvMock := &mockDriver{Driver: c.Driver, rrw: &migrate.NopRevisionReadWriter{}}\n\tc.Driver = drvMock\n\trrw, err = RevisionsForClient(ctx, c, \"\")\n\trequire.ErrorContains(t, err, \"unexpected revision read-writer type: *migrate.NopRevisionReadWriter\")\n\n\tdrvMock.rrw = &mockrrw{RevisionReadWriter: &migrate.NopRevisionReadWriter{}}\n\trrw, err = RevisionsForClient(ctx, c, \"\")\n\trequire.NoError(t, err)\n\t_, ok = rrw.(*mockrrw)\n\trequire.True(t, ok, \"RevisionsForClient should return a mockrrw\")\n}\n\nfunc TestNewEntRevisions(t *testing.T) {\n\tctx := context.Background()\n\tc, err := sqlclient.Open(ctx, \"sqlite://?mode=memory\")\n\trequire.NoError(t, err)\n\tr, err := NewEntRevisions(ctx, c)\n\trequire.NoError(t, err)\n\trunRevisionsTests(ctx, t, c.Driver, r)\n}\n\nfunc TestDirURL(t *testing.T) {\n\tlocalDir := t.TempDir()\n\ttests := []struct {\n\t\tname        string\n\t\turl         string\n\t\tcreate      bool\n\t\texpected    func() migrate.Dir\n\t\texpectedErr error\n\t}{\n\t\t{\n\t\t\tname:   \"Valid file URL\",\n\t\t\turl:    \"file://\" + localDir,\n\t\t\tcreate: false,\n\t\t\texpected: func() migrate.Dir {\n\t\t\t\td, err := migrate.NewLocalDir(localDir)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"Create local dir\",\n\t\t\turl:    \"file://\" + filepath.Join(localDir, \"new/dir\"),\n\t\t\tcreate: true,\n\t\t\texpected: func() migrate.Dir {\n\t\t\t\td, err := migrate.NewLocalDir(filepath.Join(localDir, \"new/dir\"))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"Dont create local dir\",\n\t\t\turl:         \"file://\" + filepath.Join(localDir, \"new/dir/2\"),\n\t\t\tcreate:      false,\n\t\t\texpectedErr: fmt.Errorf(\"sql/migrate: stat %s: no such file or directory\", filepath.Join(localDir, \"new/dir/2\")),\n\t\t},\n\t\t{\n\t\t\tname:        \"No scheme\",\n\t\t\turl:         localDir,\n\t\t\tcreate:      false,\n\t\t\texpectedErr: fmt.Errorf(\"missing scheme for dir url. Did you mean %q? \", \"file://\"+localDir),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdir, err := Dir(context.Background(), tt.url, tt.create)\n\t\t\tif tt.expectedErr != nil {\n\t\t\t\trequire.EqualError(t, err, tt.expectedErr.Error())\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, tt.expected(), dir)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc runRevisionsTests(ctx context.Context, t *testing.T, drv migrate.Driver, r RevisionReadWriter) {\n\t_, err := drv.ExecContext(ctx, \"CREATE VIEW v1(c1) AS SELECT 1;\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, r.Migrate(ctx))\n\n\ts, err := drv.InspectSchema(ctx, \"\", nil)\n\trequire.NoError(t, err)\n\trequire.Len(t, s.Tables, 1)\n\t_, ok := s.Table(revision.Table)\n\trequire.True(t, ok)\n\n\tcur, err := r.CurrentRevision(ctx)\n\trequire.True(t, errors.Is(err, migrate.ErrRevisionNotExist))\n\trequire.Nil(t, cur)\n\n\terr = r.WriteRevision(ctx, &migrate.Revision{\n\t\tVersion:         \"1\",\n\t\tDescription:     \"desc\",\n\t\tType:            migrate.RevisionTypeResolved,\n\t\tExecutedAt:      time.Now(),\n\t\tHash:            \"hash\",\n\t\tOperatorVersion: \"0.1.0\",\n\t})\n\trequire.NoError(t, err)\n\tcur, err = r.CurrentRevision(ctx)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"1\", cur.Version)\n\n\tnext := *cur\n\tnext.Version = \"2\"\n\trequire.NoError(t, r.WriteRevision(ctx, &next))\n\tcur, err = r.CurrentRevision(ctx)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"2\", cur.Version)\n\n\trevs, err := r.ReadRevisions(ctx)\n\trequire.NoError(t, err)\n\trequire.Len(t, revs, 2)\n\trequire.Equal(t, \"1\", revs[0].Version)\n\trequire.Equal(t, \"2\", revs[1].Version)\n\n\tid, err := r.ID(ctx, \"v0.10.1\")\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, id)\n\tid1, err := r.ID(ctx, \"v0.10.1\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, id, id1, \"identifiers should be allocated only once\")\n\n\t// Identifier is not returned as a revision.\n\trevs, err = r.ReadRevisions(ctx)\n\trequire.NoError(t, err)\n\trequire.Len(t, revs, 2, \"identifiers should not be returned as revisions\")\n\t_, err = r.ReadRevision(ctx, revisionID)\n\trequire.Error(t, err)\n\terr = r.DeleteRevision(ctx, revisionID)\n\trequire.Error(t, err)\n\terr = r.WriteRevision(ctx, &migrate.Revision{Version: revisionID})\n\trequire.Error(t, err)\n\n\tcur, err = r.CurrentRevision(ctx)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"2\", cur.Version)\n\trequire.NoError(t, r.DeleteRevision(ctx, \"2\"))\n\tcur, err = r.CurrentRevision(ctx)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"1\", cur.Version)\n\trequire.NoError(t, r.DeleteRevision(ctx, \"1\"))\n\tcur, err = r.CurrentRevision(ctx)\n\trequire.True(t, errors.Is(err, migrate.ErrRevisionNotExist))\n\trequire.Nil(t, cur)\n\trevs, err = r.ReadRevisions(ctx)\n\trequire.NoError(t, err)\n\trequire.Len(t, revs, 0)\n\tid1, err = r.ID(ctx, \"v0.10.1\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, id, id1)\n}\n\ntype (\n\tmockDriver struct {\n\t\tmigrate.Driver\n\t\trrw migrate.RevisionReadWriter\n\t}\n\tmockrrw struct {\n\t\tmigrate.RevisionReadWriter\n\t}\n)\n\nfunc (m *mockDriver) RevisionsReadWriter(context.Context, string) (migrate.RevisionReadWriter, error) {\n\treturn m.rrw, nil\n}\n\nfunc (*mockrrw) CurrentRevision(context.Context) (*migrate.Revision, error) { return nil, nil }\nfunc (*mockrrw) Migrate(context.Context) error                              { return nil }\nfunc (*mockrrw) ID(context.Context, string) (string, error)                 { return \"\", nil }\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/testdata/broken/1.sql",
    "content": "CREATE TABLE `users` (`id` int NOT NULL PRIMARY KEY);"
  },
  {
    "path": "cmd/atlas/internal/migrate/testdata/broken/2.sql",
    "content": "ALTER TABLE `users` ADD COLUMN `happy` boolean NOT NULL DEFAULT true;"
  },
  {
    "path": "cmd/atlas/internal/migrate/testdata/broken/3.sql",
    "content": "CREATE TABLE `pets` (`id` int NOT NULL PRIMARY KEY);\nTHIS LINE ADDS A SYNTAX ERROR;"
  },
  {
    "path": "cmd/atlas/internal/migrate/testdata/broken/atlas.sum",
    "content": "h1:0YTkvowN+aAuYuJY5ZANPAq6QAZ0wAXunU9sUXsuZcI=\n1.sql h1:twN+zPVp8JzWEUcPPfNIT6/62Wa08dfxxZhT4gZxBzg=\n2.sql h1:KHLlrSPwSjbp4+KrpQHwYZf8zlSIiAR7MS3H2yd1yeE=\n3.sql h1:iTKab5MEzWsTdVVDkCUWmateRs9XRNpal/cxqlCYsmQ=\n"
  },
  {
    "path": "cmd/atlas/internal/migrate/testdata/fixed/1.sql",
    "content": "CREATE TABLE `users` (`id` int NOT NULL PRIMARY KEY);"
  },
  {
    "path": "cmd/atlas/internal/migrate/testdata/fixed/2.sql",
    "content": "ALTER TABLE `users` ADD COLUMN `happy` boolean NOT NULL DEFAULT true;"
  },
  {
    "path": "cmd/atlas/internal/migrate/testdata/fixed/3.sql",
    "content": "CREATE TABLE `pets` (`id` int NOT NULL PRIMARY KEY);\nALTER TABLE `pets` ADD COLUMN `happy` boolean NULL;"
  },
  {
    "path": "cmd/atlas/internal/migrate/testdata/fixed/atlas.sum",
    "content": "h1:oNV0f9HzMMCf2pzF+sA6CmsSHGjdkWYmcTjoc/lWxLs=\n1.sql h1:twN+zPVp8JzWEUcPPfNIT6/62Wa08dfxxZhT4gZxBzg=\n2.sql h1:KHLlrSPwSjbp4+KrpQHwYZf8zlSIiAR7MS3H2yd1yeE=\n3.sql h1:osHrPgu8uNgd6j09XCiyBQWWEh9aAmwjRgzdZZgm68M=\n"
  },
  {
    "path": "cmd/atlas/internal/migratelint/lint.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage migratelint\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/sqlparse\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n)\n\ntype (\n\t// A ChangeDetector takes a migration directory and splits it into the \"base\" files (already merged) and new ones.\n\tChangeDetector interface {\n\t\t// DetectChanges splits the files of a migration directory into the \"base\" files (already merged) and new ones.\n\t\tDetectChanges(context.Context) ([]migrate.File, []migrate.File, error)\n\t}\n\n\t// A ChangeLoader takes a set of migration files and will create multiple schema.Changes out of it.\n\tChangeLoader interface {\n\t\t// LoadChanges converts each of the given migration files into one Changes.\n\t\tLoadChanges(context.Context, []migrate.File) (*Changes, error)\n\t}\n\n\t// Changes holds schema changes information returned by the loader.\n\tChanges struct {\n\t\tFrom, To *schema.Realm    // Current and desired schema.\n\t\tFiles    []*sqlcheck.File // Files for moving from current to desired state.\n\t}\n)\n\ntype (\n\t// GitChangeDetector implements the ChangeDetector interface by utilizing a git repository.\n\tGitChangeDetector struct {\n\t\twork string      // path to the git working directory (i.e. -C)\n\t\tbase string      // name of the base branch (e.g. master)\n\t\tpath string      // path of the migration directory relative to the repository root (in slash notation)\n\t\tdir  migrate.Dir // the migration directory to load migration files from\n\t}\n\n\t// GitChangeDetectorOption allows configuring GitChangeDetector with functional arguments.\n\tGitChangeDetectorOption func(*GitChangeDetector) error\n)\n\n// NewGitChangeDetector configures a new GitChangeDetector.\nfunc NewGitChangeDetector(dir migrate.Dir, opts ...GitChangeDetectorOption) (*GitChangeDetector, error) {\n\tif dir == nil {\n\t\treturn nil, errors.New(\"internal/ci: dir cannot be nil\")\n\t}\n\td := &GitChangeDetector{dir: dir}\n\tfor _, opt := range opts {\n\t\tif err := opt(d); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif d.base == \"\" {\n\t\td.base = \"master\"\n\t}\n\tif d.path == \"\" {\n\t\td.path = \"migrations\"\n\t}\n\treturn d, nil\n}\n\n// WithWorkDir configures the git working directory for a GitChangeDetector.\nfunc WithWorkDir(work string) GitChangeDetectorOption {\n\treturn func(d *GitChangeDetector) error {\n\t\td.work = work\n\t\treturn nil\n\t}\n}\n\n// WithBase configures the git base branch name for a GitChangeDetector.\nfunc WithBase(base string) GitChangeDetectorOption {\n\treturn func(d *GitChangeDetector) error {\n\t\td.base = base\n\t\treturn nil\n\t}\n}\n\n// WithMigrationsPath configures the path for the migration directory.\nfunc WithMigrationsPath(path string) GitChangeDetectorOption {\n\treturn func(d *GitChangeDetector) error {\n\t\td.path = filepath.ToSlash(path)\n\t\treturn nil\n\t}\n}\n\n// DetectChanges implements the ChangeDetector interface.\nfunc (d *GitChangeDetector) DetectChanges(ctx context.Context) ([]migrate.File, []migrate.File, error) {\n\tif _, err := exec.LookPath(\"git\"); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"lookup git: %w\", err)\n\t}\n\tvar args []string\n\tif d.work != \"\" {\n\t\targs = append(args, \"-C\", d.work)\n\t}\n\targs = append(args, \"--no-pager\", \"diff\", \"--name-only\", \"--diff-filter=A\", d.base, \"HEAD\", d.path)\n\tbuf, err := exec.CommandContext(ctx, \"git\", args...).CombinedOutput()\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"git diff: %w\", err)\n\t}\n\tdiff := strings.Split(string(buf), \"\\n\")\n\tnames := make(map[string]struct{}, len(diff))\n\tfor i := range diff {\n\t\tnames[filepath.Base(diff[i])] = struct{}{}\n\t}\n\tfiles, err := d.dir.Files()\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"reading migration directory: %w\", err)\n\t}\n\t// Iterate over the migration files. If we find a file, that has been added in the diff between base and head,\n\t// every migration file preceding it can be considered old, the file itself and everything thereafter new,\n\t// since Atlas assumes a linear migration history.\n\tfor i, f := range files {\n\t\tif _, ok := names[f.Name()]; ok {\n\t\t\treturn files[:i], files[i:], nil\n\t\t}\n\t}\n\treturn files, nil, nil\n}\n\nvar (\n\t_ ChangeDetector = (*GitChangeDetector)(nil)\n\t_ ChangeDetector = (*DirChangeDetector)(nil)\n)\n\n// A DirChangeDetector implements the ChangeDetector\n// interface by comparing two migration directories.\ntype DirChangeDetector struct {\n\t// Base and Head are the migration directories to compare.\n\t// Base represents the current state, Head the desired state.\n\tBase, Head migrate.Dir\n}\n\n// DetectChanges implements migratelint.ChangeDetector.\nfunc (d DirChangeDetector) DetectChanges(context.Context) ([]migrate.File, []migrate.File, error) {\n\tbaseS, err := d.Base.Checksum()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\theadS, err := d.Head.Checksum()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tfiles, err := d.Head.Files()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tfor i := range headS {\n\t\tif len(baseS)-1 < i || baseS[i] != headS[i] {\n\t\t\treturn files[:i], files[i:], nil\n\t\t}\n\t}\n\treturn files, nil, nil\n}\n\n// latestChange implements the ChangeDetector by selecting the latest N files.\ntype latestChange struct {\n\tn   int         // number of (latest) files considered new.\n\tdir migrate.Dir // migration directory to load migration files from.\n}\n\n// LatestChanges implements the ChangeDetector interface by selecting the latest N files as new.\n// It is useful for executing analysis on files in development before they are committed or on\n// all files in a directory.\nfunc LatestChanges(dir migrate.Dir, n int) ChangeDetector {\n\treturn &latestChange{n: n, dir: dir}\n}\n\n// DetectChanges implements the ChangeDetector interface.\nfunc (d *latestChange) DetectChanges(context.Context) ([]migrate.File, []migrate.File, error) {\n\tfiles, err := d.dir.Files()\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"internal/ci: reading migration directory: %w\", err)\n\t}\n\t// In case n is -1 or greater than the\n\t// number of files, return all files.\n\tif len(files) <= d.n || d.n < 0 {\n\t\treturn nil, files, nil\n\t}\n\treturn files[:len(files)-d.n], files[len(files)-d.n:], nil\n}\n\n// DevLoader implements the ChangesLoader interface using a dev-driver.\ntype DevLoader struct {\n\t// Dev environment used as a sandbox instantiated to the starting point (e.g. base branch).\n\tDev *sqlclient.Client\n}\n\n// LoadChanges implements the ChangesLoader interface.\nfunc (d *DevLoader) LoadChanges(ctx context.Context, base, files []migrate.File) (diff *Changes, err error) {\n\tunlock, err := d.lock(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer unlock()\n\t// Clean up after ourselves.\n\trestore, err := d.Dev.Driver.Snapshot(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"taking database snapshot: %w\", err)\n\t}\n\tdefer func() {\n\t\tif err2 := restore(ctx); err2 != nil {\n\t\t\terr = errors.Join(err, fmt.Errorf(\"restore dev-database snapshot: %w\", err2))\n\t\t}\n\t}()\n\tcurrent, err := d.base(ctx, base)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdiff = &Changes{\n\t\tFrom:  current,\n\t\tFiles: make([]*sqlcheck.File, len(files)),\n\t}\n\tcks := make([]int, 0, len(files))\n\tfor i, f := range files {\n\t\tdiff.Files[i] = &sqlcheck.File{\n\t\t\tFile:   f,\n\t\t\tFrom:   current,\n\t\t\tParser: sqlparse.ParserFor(d.Dev.Name),\n\t\t}\n\t\t// Skip checkpoint files and process them separately at the end.\n\t\tif ck, ok := f.(migrate.CheckpointFile); ok && ck.IsCheckpoint() {\n\t\t\tcks = append(cks, i)\n\t\t\tcontinue\n\t\t}\n\t\t// A common case is when importing a project to Atlas the baseline\n\t\t// migration file might be very long. However, since we execute on\n\t\t// a clean database, the per-statement analysis is not needed.\n\t\tif len(base) == 0 && i == 0 {\n\t\t\tcurrent, err = d.first(ctx, diff.Files[i], current)\n\t\t} else {\n\t\t\tcurrent, err = d.next(ctx, diff.Files[i], current)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdiff.Files[i].To = current\n\t}\n\tdiff.To = current\n\t// For each checkpoint file, restore the dev environment\n\t// to the base point (clean) and load its changes.\n\tfor _, i := range cks {\n\t\tif err := restore(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcurrent, err := d.inspect(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif _, err := d.next(ctx, diff.Files[i], current); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn diff, nil\n}\n\n// base brings the dev environment to the base point and returns its state. It skips to the first checkpoint,\n// if there is one, assuming the history is replay-able before that point as this was tested in previous runs.\nfunc (d *DevLoader) base(ctx context.Context, base []migrate.File) (*schema.Realm, error) {\n\tif i := migrate.FilesLastIndex(base, func(f migrate.File) bool {\n\t\tck, ok := f.(migrate.CheckpointFile)\n\t\treturn ok && ck.IsCheckpoint()\n\t}); i != -1 {\n\t\tbase = base[i:]\n\t}\n\tfor _, f := range base {\n\t\tstmts, err := d.stmts(ctx, f, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor _, s := range stmts {\n\t\t\tif _, err := d.Dev.ExecContext(ctx, s.Text); err != nil {\n\t\t\t\treturn nil, &FileError{File: f.Name(), Err: fmt.Errorf(\"executing statement: %w\", err), Pos: s.Pos}\n\t\t\t}\n\t\t}\n\t}\n\treturn d.inspect(ctx)\n}\n\n// first is a version of \"next\" but is used when linting the first migration file. In this case we do not\n// need to analyze each statement, but the entire result of the file (much faster). For example, a baseline\n// file or the first migration when running 'schema apply' might contain thousands of lines.\nfunc (d *DevLoader) first(ctx context.Context, f *sqlcheck.File, start *schema.Realm) (current *schema.Realm, err error) {\n\tstmts, err := d.stmts(ctx, f.File, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// We define the max number of apply-inspect-diff cycles to 10,\n\t// to limit our linting time for baseline/first migration files.\n\tconst maxStmtLoop = 10\n\tif len(stmts) <= maxStmtLoop {\n\t\treturn d.nextStmts(ctx, f, stmts, start)\n\t}\n\tfor _, s := range stmts {\n\t\tif _, err := d.Dev.ExecContext(ctx, s.Text); err != nil {\n\t\t\treturn nil, &FileError{File: f.Name(), Err: fmt.Errorf(\"executing statement: %s: %w\", s.Text, err), Pos: s.Pos}\n\t\t}\n\t}\n\tif current, err = d.inspect(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\tchanges, err := d.Dev.RealmDiff(start, current)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tf.Changes = append(f.Changes, &sqlcheck.Change{\n\t\tChanges: changes,\n\t\tStmt: &migrate.Stmt{\n\t\t\tPos: 0, // Beginning of the file.\n\t\t},\n\t})\n\tf.Sum = changes\n\treturn current, nil\n}\n\n// next returns the next state of the database after executing the statements in\n// the file. The changes detected by the statements are attached to the file.\nfunc (d *DevLoader) next(ctx context.Context, f *sqlcheck.File, start *schema.Realm) (*schema.Realm, error) {\n\tstmts, err := d.stmts(ctx, f.File, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn d.nextStmts(ctx, f, stmts, start)\n}\n\n// nextStmts is a version of \"next\" but accepts the statements to execute.\nfunc (d *DevLoader) nextStmts(ctx context.Context, f *sqlcheck.File, stmts []*migrate.Stmt, start *schema.Realm) (current *schema.Realm, err error) {\n\tcurrent = start\n\tfor _, s := range stmts {\n\t\tif _, err := d.Dev.ExecContext(ctx, s.Text); err != nil {\n\t\t\treturn nil, &FileError{File: f.Name(), Err: fmt.Errorf(\"executing statement: %s: %w\", s.Text, err), Pos: s.Pos}\n\t\t}\n\t\tnext, err := d.inspect(ctx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tchanges, err := d.Dev.RealmDiff(current, next)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcurrent = next\n\t\tf.Changes = append(f.Changes, &sqlcheck.Change{\n\t\t\tStmt:    s,\n\t\t\tChanges: d.mayFix(s.Text, changes),\n\t\t})\n\t}\n\tif f.Sum, err = d.Dev.RealmDiff(start, current); err != nil {\n\t\treturn nil, err\n\t}\n\treturn current, nil\n}\n\n// mayFix uses the sqlparse package for fixing or attaching more info to the changes.\nfunc (d *DevLoader) mayFix(stmt string, changes schema.Changes) schema.Changes {\n\tp := sqlparse.ParserFor(d.Dev.Name)\n\tif p == nil {\n\t\treturn changes\n\t}\n\tif fixed, err := p.FixChange(d.Dev.Driver, stmt, changes); err == nil {\n\t\treturn fixed\n\t}\n\treturn changes\n}\n\n// inspect the realm and filter by schema if we are connected to one.\nfunc (d *DevLoader) inspect(ctx context.Context) (*schema.Realm, error) {\n\tif d.Dev.URL.Schema == \"\" {\n\t\treturn d.Dev.InspectRealm(ctx, &schema.InspectRealmOption{})\n\t}\n\tns, err := d.Dev.InspectSchema(ctx, \"\", &schema.InspectOptions{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Normalize the returned realm to\n\t// look like InspectRealm output.\n\tif ns.Name == \"\" {\n\t\tns.Name = d.Dev.URL.Schema\n\t}\n\tif ns.Realm == nil {\n\t\tns.Realm = schema.NewRealm(ns)\n\t}\n\treturn ns.Realm, nil\n}\n\n// lock database so no one else interferes with our change detection.\nfunc (d *DevLoader) lock(ctx context.Context) (schema.UnlockFunc, error) {\n\tname := \"atlas_lint\"\n\t// In case the client is connected to specific schema,\n\t// minimize the lock resolution to the schema name.\n\tif s := d.Dev.URL.Schema; s != \"\" {\n\t\tname = fmt.Sprintf(\"%s_%s\", name, s)\n\t}\n\tunlock, err := d.Dev.Driver.Lock(ctx, name, 0)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"acquiring database lock: %w\", err)\n\t}\n\treturn unlock, nil\n}\n\n// FileError represents an error that occurred while processing a file.\ntype FileError struct {\n\tFile string\n\tErr  error // Atlas or database error.\n\tPos  int   // Position error, if known.\n}\n\nfunc (e FileError) Error() string { return e.Err.Error() }\n\nfunc (e FileError) Unwrap() error { return e.Err }\n"
  },
  {
    "path": "cmd/atlas/internal/migratelint/lint_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage migratelint\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"slices\"\n\t\"strings\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/fatih/color\"\n)\n\n// Runner is used to execute migration linting.\ntype Runner struct {\n\t// DevClient configures the \"dev driver\" to calculate\n\t// migration changes by the driver.\n\tDev *sqlclient.Client\n\n\t// RunChangeDetector configures the ChangeDetector to\n\t// be used by the runner.\n\tChangeDetector ChangeDetector\n\n\t// Dir is used for scanning and validating the migration directory.\n\tDir migrate.Dir\n\n\t// Analyzers defines the analysis to run on each migration file.\n\tAnalyzers []sqlcheck.Analyzer\n\n\t// ReportWriter writes the summary report.\n\tReportWriter ReportWriter\n\n\t// summary report. reset on each run.\n\tsum *SummaryReport\n}\n\n// Run executes migration linting.\nfunc (r *Runner) Run(ctx context.Context) error {\n\tswitch err := r.summary(ctx); err.(type) {\n\tcase nil:\n\t\tif err := r.ReportWriter.WriteReport(r.sum); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// If any of the analyzers or the steps\n\t\t// returns an error, fail silently.\n\t\tfor _, f := range r.sum.Files {\n\t\t\tif f.Error != \"\" {\n\t\t\t\treturn SilentError{error: errors.New(f.Error)}\n\t\t\t}\n\t\t}\n\t\tfor _, s := range r.sum.Steps {\n\t\t\t// Currently, we piggyback step errors\n\t\t\t// (such as non-linear) on FileReport.\n\t\t\tif s.Result != nil && s.Error != \"\" {\n\t\t\t\treturn SilentError{error: errors.New(s.Error)}\n\t\t\t}\n\t\t}\n\t\treturn nil\n\tcase *FileError:\n\t\tif err := r.ReportWriter.WriteReport(r.sum); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn SilentError{error: err}\n\tdefault:\n\t\treturn err\n\t}\n}\n\n// A list of steps in CI report.\nconst (\n\tStepIntegrityCheck = \"Migration Integrity Check\"\n\tStepDetectChanges  = \"Detect New Migration Files\"\n\tStepLoadChanges    = \"Replay Migration Files\"\n\tStepAnalyzeFile    = \"Analyze %s\"\n)\n\nfunc (r *Runner) summary(ctx context.Context) error {\n\tr.sum = NewSummaryReport(r.Dev, r.Dir)\n\tdefer func() { r.sum.End = time.Now() }()\n\n\t// Integrity check.\n\tswitch err := migrate.Validate(r.Dir); {\n\tcase errors.Is(err, migrate.ErrChecksumNotFound):\n\tcase err != nil:\n\t\tvar (\n\t\t\terr = &FileError{File: migrate.HashFileName, Err: err}\n\t\t\trep = &FileReport{Name: migrate.HashFileName, Error: err.Error()}\n\t\t)\n\t\tif csErr := (&migrate.ChecksumError{}); errors.As(err, &csErr) {\n\t\t\terr.Pos = csErr.Pos\n\t\t\trep = &FileReport{\n\t\t\t\tName:  migrate.HashFileName,\n\t\t\t\tError: fmt.Sprintf(\"%s (atlas.sum): L%d: %s was %s\", csErr, csErr.Line, csErr.File, csErr.Reason),\n\t\t\t}\n\t\t}\n\t\tr.sum.Files = append(r.sum.Files, rep)\n\t\treturn r.sum.StepError(StepIntegrityCheck, fmt.Sprintf(\"File %s is invalid\", migrate.HashFileName), err)\n\tdefault:\n\t\t// If the hash file exists, it is valid.\n\t\tif _, err := fs.Stat(r.Dir, migrate.HashFileName); err == nil {\n\t\t\tr.sum.StepResult(StepIntegrityCheck, fmt.Sprintf(\"File %s is valid\", migrate.HashFileName), nil)\n\t\t}\n\t}\n\n\t// Detect new migration files.\n\tbase, feat, err := r.ChangeDetector.DetectChanges(ctx)\n\tswitch err := err.(type) {\n\t// No error.\n\tcase nil:\n\t\tr.sum.StepResult(StepDetectChanges, fmt.Sprintf(\"Found %d new migration files (from %d total)\", len(feat), len(base)+len(feat)), nil)\n\t// Error that should be reported, but not halt the lint.\n\tcase interface{ StepReport() *StepReport }:\n\t\tr.sum.Steps = append(r.sum.Steps, err.StepReport())\n\tdefault:\n\t\treturn r.sum.StepError(StepDetectChanges, \"Failed find new migration files\", err)\n\t}\n\tif len(base) > 0 {\n\t\tr.sum.FromV = base[len(base)-1].Version()\n\t}\n\tif len(feat) > 0 {\n\t\tr.sum.ToV = feat[len(feat)-1].Version()\n\t}\n\tr.sum.TotalFiles = len(feat)\n\n\t// Load files into changes.\n\tl := &DevLoader{Dev: r.Dev}\n\tdiff, err := l.LoadChanges(ctx, base, feat)\n\tif err != nil {\n\t\tif fr := (&FileError{}); errors.As(err, &fr) {\n\t\t\tr.sum.Files = append(r.sum.Files, &FileReport{Name: fr.File, Error: err.Error()})\n\t\t}\n\t\treturn r.sum.StepError(StepLoadChanges, \"Failed loading changes on dev database\", err)\n\t}\n\tr.sum.StepResult(StepLoadChanges, fmt.Sprintf(\"Loaded %d changes on dev database\", len(diff.Files)), nil)\n\tr.sum.WriteSchema(r.Dev, diff)\n\n\t// Analyze files.\n\treturn r.analyze(ctx, diff.Files)\n}\n\n// analyze runs the analysis on the given files.\nfunc (r *Runner) analyze(ctx context.Context, files []*sqlcheck.File) error {\n\tfor _, f := range files {\n\t\tvar (\n\t\t\tes []string\n\t\t\tnl = nolintRules(f)\n\t\t\tfr = NewFileReport(f)\n\t\t)\n\t\tif nl.ignored {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, az := range r.Analyzers {\n\t\t\terr := func(az sqlcheck.Analyzer) (rerr error) {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif rc := recover(); rc != nil {\n\t\t\t\t\t\tvar name string\n\t\t\t\t\t\tif n, ok := az.(sqlcheck.NamedAnalyzer); ok {\n\t\t\t\t\t\t\tname = fmt.Sprintf(\" (%s)\", n.Name())\n\t\t\t\t\t\t}\n\t\t\t\t\t\trerr = fmt.Errorf(\"skip crashed analyzer %s: %v\", name, rc)\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\treturn az.Analyze(ctx, &sqlcheck.Pass{\n\t\t\t\t\tFile:     f,\n\t\t\t\t\tDev:      r.Dev,\n\t\t\t\t\tReporter: nl.reporterFor(fr, az),\n\t\t\t\t})\n\t\t\t}(az)\n\t\t\t// If the last report was skipped,\n\t\t\t// skip emitting its error.\n\t\t\tif err != nil && !nl.skipped {\n\t\t\t\tes = append(es, err.Error())\n\t\t\t}\n\t\t}\n\t\tfr.Error = strings.Join(es, \"; \")\n\t\tr.sum.Files = append(r.sum.Files, fr)\n\t\tr.sum.StepResult(\n\t\t\tfmt.Sprintf(StepAnalyzeFile, f.Name()),\n\t\t\tfmt.Sprintf(\"%d reports were found in analysis\", len(fr.Reports)),\n\t\t\tfr,\n\t\t)\n\t}\n\treturn nil\n}\n\nvar (\n\t// TemplateFuncs are global functions available in templates.\n\tTemplateFuncs = template.FuncMap{\n\t\t\"json\": func(v any, args ...string) (string, error) {\n\t\t\tvar (\n\t\t\t\tb   []byte\n\t\t\t\terr error\n\t\t\t)\n\t\t\tswitch len(args) {\n\t\t\tcase 0:\n\t\t\t\tb, err = json.Marshal(v)\n\t\t\tcase 1:\n\t\t\t\tb, err = json.MarshalIndent(v, \"\", args[0])\n\t\t\tdefault:\n\t\t\t\tb, err = json.MarshalIndent(v, args[0], args[1])\n\t\t\t}\n\t\t\treturn string(b), err\n\t\t},\n\t\t\"sub\":       func(i, j int) int { return i - j },\n\t\t\"add\":       func(i, j int) int { return i + j },\n\t\t\"repeat\":    strings.Repeat,\n\t\t\"join\":      strings.Join,\n\t\t\"underline\": color.New(color.Underline, color.Attribute(90)).Sprint,\n\t\t\"gray\":      color.New(color.Reset, color.Attribute(90)).Sprint,\n\t\t\"lower\":     strings.ToLower,\n\t\t\"maxWidth\": func(s string, n int) []string {\n\t\t\tvar (\n\t\t\t\tj, k  int\n\t\t\t\twords = strings.Fields(s)\n\t\t\t\tlines = make([]string, 0, len(words))\n\t\t\t)\n\t\t\tfor i := 0; i < len(words); i++ {\n\t\t\t\tif k+len(words[i]) > n {\n\t\t\t\t\tlines = append(lines, strings.Join(words[j:i], \" \"))\n\t\t\t\t\tk, j = 0, i\n\t\t\t\t}\n\t\t\t\tk += len(words[i])\n\t\t\t}\n\t\t\treturn append(lines, strings.Join(words[j:], \" \"))\n\t\t},\n\t\t\"cyan\":         color.CyanString,\n\t\t\"green\":        color.HiGreenString,\n\t\t\"red\":          color.HiRedString,\n\t\t\"redBgWhiteFg\": color.New(color.FgHiWhite, color.BgHiRed).SprintFunc(),\n\t\t\"yellow\":       color.YellowString,\n\t\t\"colorize\": func(cc, text string) string {\n\t\t\tswitch cc {\n\t\t\tcase \"cyan\":\n\t\t\t\treturn color.CyanString(text)\n\t\t\tcase \"green\":\n\t\t\t\treturn color.HiGreenString(text)\n\t\t\tcase \"red\":\n\t\t\t\treturn color.HiRedString(text)\n\t\t\tcase \"yellow\":\n\t\t\t\treturn color.YellowString(text)\n\t\t\tdefault:\n\t\t\t\treturn text\n\t\t\t}\n\t\t},\n\t}\n\t// DefaultTemplate is the default template used by the CI job.\n\tDefaultTemplate = template.Must(template.New(\"report\").\n\t\tFuncs(TemplateFuncs).\n\t\tParse(`\n{{- if or .Files .NonFileReports }}\n  {{- $total := len .Files }}{{- with .TotalFiles }}{{- $total = . }}{{ end }}\n  {{- $s := \"s\" }}{{ if eq $total 1 }}{{ $s = \"\" }}{{ end }}\n  {{- if and .FromV .ToV }}\n    {{- printf \"Analyzing changes from version %s to %s\" (cyan .FromV) (cyan .ToV) }}\n  {{- else if .ToV }}\n    {{- printf \"Analyzing changes until version %s\" (cyan .ToV) }}\n  {{- else }}\n    {{- printf \"Analyzing changes\" }}\n  {{- end }}\n  {{- if $total }}\n    {{- printf \" (%d migration%s in total):\\n\" $total $s }}\n  {{- else }}\n    {{- println \":\" }}\n  {{- end }}\n  {{- println }}\n  {{- with .NonFileReports }}\n    {{- range $i, $s := . }}\n      {{- println (yellow \"  --\") (lower $s.Name) }}\n      {{- range $i, $r := $s.Result.Reports }}\n        {{- if $r.Text }}\n           {{- printf \"    %s %s:\\n\" (yellow \"--\") $r.Text }}\n        {{- end }}\n        {{- range $d := $r.Diagnostics }}\n          {{- $prefix := printf \"    %s \" (cyan \"--\") }}\n          {{- print $prefix }}\n          {{- $lines := maxWidth $d.Text (sub 85 (len $prefix)) }}\n          {{- range $i, $line := $lines }}{{- if $i }}{{- print \"       \" }}{{- end }}{{- println $line }}{{- end }}\n        {{- end }}\n        {{- $fixes := $s.Result.SuggestedFixes }}\n        {{- if $fixes }}\n          {{- $s := \"es\" }}{{- if eq (len $fixes) 1 }}{{ $s = \"\" }}{{ end }}\n          {{- printf \"    %s suggested fix%s:\\n\" (yellow \"--\") $s }}\n          {{- range $f := $fixes }}\n            {{- $prefix := printf \"      %s \" (cyan \"->\") }}\n            {{- print $prefix }}\n            {{- $lines := maxWidth $f.Message (sub 85 (len $prefix)) }}\n            {{- range $i, $line := $lines }}{{- if $i }}{{- print \"         \" }}{{- end }}{{- println $line }}{{- end }}\n          {{- end }}\n        {{- end }}\n      {{- end }}\n    {{- end }}\n    {{- println }}\n  {{- end }}\n  {{- range $i, $f := .Files }}\n    {{- /* Replay or checksum errors. */ -}}\n    {{- if and $f.Error (eq $f.File nil) (eq $i (sub (len $.Files) 1)) }}\n      {{- printf \"  %s\\n\\n\" (redBgWhiteFg (printf \"Error: %s\" $f.Error)) }}\n      {{- break }}\n    {{- end }}\n    {{- $heading := printf \"analyzing version %s\" (cyan $f.Version) }}\n    {{- $headinglen := len (printf \"analyzing version %s\" $f.Version) }}\n    {{- println (yellow \"  --\") $heading }}\n    {{- if and $f.Error (not $f.Reports) }}\n       {{- printf \"Error: %s\\n\" $f.Name $f.Error }}\n       {{- continue }}\n    {{- end }}\n    {{- range $i, $r := $f.Reports }}\n      {{- if $r.Text }}\n         {{- printf \"    %s %s:\\n\" (yellow \"--\") $r.Text }}\n      {{- else if $r.Diagnostics }}\n         {{- printf \"    %s Unnamed diagnostics detected:\\n\" (yellow \"--\") }}\n      {{- end }}\n      {{- range $d := $r.Diagnostics }}\n        {{- $prefix := printf \"      %s L%d: \" (cyan \"--\") ($f.Line $d.Pos) }}\n        {{- print $prefix }}\n        {{- $link := (underline (print \"https://atlasgo.io/lint/analyzers#\" $d.Code)) }}{{ if not $d.Code }}{{ $link = \"\" }}{{ end }}\n        {{- $text := printf \"%s %s\" $d.Text $link }}\n        {{- $lines := maxWidth $text (sub 85 (len $prefix)) }}\n        {{- range $i, $line := $lines }}{{- if $i }}{{- print \"         \" }}{{- end }}{{- println $line }}{{- end }}\n      {{- end }}\n    {{- else }}\n      {{- printf \"    %s no diagnostics found\\n\" (cyan \"--\") }}\n    {{- end }}\n    {{- $fixes := $f.SuggestedFixes }}\n    {{- if $fixes }}\n      {{- $s := \"es\" }}{{- if eq (len $fixes) 1 }}{{ $s = \"\" }}{{ end }}\n      {{- printf \"    %s suggested fix%s:\\n\" (yellow \"--\") $s }}\n      {{- range $f := $fixes }}\n        {{- $prefix := printf \"      %s \" (cyan \"->\") }}\n        {{- print $prefix }}\n        {{- $lines := maxWidth $f.Message (sub 85 (len $prefix)) }}\n        {{- range $i, $line := $lines }}{{- if $i }}{{- print \"         \" }}{{- end }}{{- println $line }}{{- end }}\n      {{- end }}\n    {{- end }}\n    {{- if or (not $f.Error) $f.Reports }}\n      {{- printf \"  %s ok (%s)\\n\" (yellow \"--\") (yellow (.End.Sub .Start).String) }}\n    {{- end }}\n    {{- println }}\n  {{- end }}\n  {{- println (cyan \"  -------------------------\") }}\n  {{- printf \"  %s %s\\n\" (yellow \"--\") (.End.Sub .Start).String }}\n  {{- with .VersionStatuses }}\n\t{{- printf \"  %s %s\\n\" (yellow \"--\") . }}\n  {{- end }}\n  {{- with .TotalChanges }}\n    {{- $s := \"s\" }}{{ if eq . 1 }}{{ $s = \"\" }}{{ end }}\n\t{{- printf \"  %s %d schema change%s\\n\" (yellow \"--\") . $s }}\n  {{- end }}\n  {{- with .DiagnosticsCount }}\n    {{- $s := \"s\" }}{{ if eq . 1 }}{{ $s = \"\" }}{{ end }}\n\t{{- printf \"  %s %d diagnostic%s\\n\" (yellow \"--\") . $s }}\n  {{- end }}\n{{- end -}}\n`))\n\t// JSONTemplate is the JSON template used by CI wrappers.\n\tJSONTemplate = template.Must(template.New(\"json\").\n\t\tFuncs(TemplateFuncs).\n\t\tParse(\"{{ json . }}\"))\n)\n\ntype (\n\t// A SummaryReport contains a summary of the analysis of all files.\n\t// It is used as an input to templates to report the CI results.\n\tSummaryReport struct {\n\t\tURL string `json:\"URL,omitempty\"` // URL of the report, if exists.\n\n\t\t// Env holds the environment information.\n\t\tEnv struct {\n\t\t\tDriver string         `json:\"Driver,omitempty\"` // Driver name.\n\t\t\tURL    *sqlclient.URL `json:\"URL,omitempty\"`    // URL to dev database.\n\t\t\tDir    string         `json:\"Dir,omitempty\"`    // Path to migration directory.\n\t\t}\n\n\t\t// Schema versions found by the runner.\n\t\tSchema struct {\n\t\t\tCurrent string `json:\"Current,omitempty\"` // Current schema.\n\t\t\tDesired string `json:\"Desired,omitempty\"` // Desired schema.\n\t\t}\n\n\t\t// Steps of the analysis. Added in verbose mode.\n\t\tSteps []*StepReport `json:\"Steps,omitempty\"`\n\n\t\t// Files reports. Non-empty in case there are findings.\n\t\tFiles []*FileReport `json:\"Files,omitempty\"`\n\n\t\t// Logging only info.\n\t\tStart      time.Time `json:\"-\"` // Start time of the analysis.\n\t\tEnd        time.Time `json:\"-\"` // End time of the analysis.\n\t\tFromV, ToV string    `json:\"-\"` // From and to versions.\n\t\tTotalFiles int       `json:\"-\"` // Total number of files to analyze.\n\n\t\t// A warning to be printed to the terminal, such as a license warning.\n\t\tWarning *struct {\n\t\t\tTitle string\n\t\t\tText  string\n\t\t} `json:\"-\"`\n\t}\n\n\t// FileChange specifies whether the file was added, deleted or changed.\n\tFileChange string\n\n\t// StepReport contains a summary of the analysis of a single step.\n\tStepReport struct {\n\t\tName   string      `json:\"Name,omitempty\"`   // Step name.\n\t\tText   string      `json:\"Text,omitempty\"`   // Step description.\n\t\tError  string      `json:\"Error,omitempty\"`  // Error that cause the execution to halt.\n\t\tResult *FileReport `json:\"Result,omitempty\"` // Result of the step. For example, a diagnostic.\n\n\t\t// A warning to be printed to the terminal, such as a license warning.\n\t\tWarning struct {\n\t\t\tTitle string `json:\"Title,omitempty\"`\n\t\t\tText  string `json:\"Text,omitempty\"`\n\t\t} `json:\"-\"`\n\t}\n\n\t// FileReport contains a summary of the analysis of a single file.\n\tFileReport struct {\n\t\tName    string            `json:\"Name,omitempty\"`    // Name of the file.\n\t\tText    string            `json:\"Text,omitempty\"`    // Contents of the file.\n\t\tReports []sqlcheck.Report `json:\"Reports,omitempty\"` // List of reports.\n\t\tError   string            `json:\"Error,omitempty\"`   // File specific error.\n\t\tChange  FileChange        `json:\"Change,omitempty\"`  // Change of the file.\n\n\t\t// Logging only info.\n\t\tStart          time.Time `json:\"-\"` // Start time of the analysis.\n\t\tEnd            time.Time `json:\"-\"` // End time of the analysis.\n\t\t*sqlcheck.File `json:\"-\"`           // Underlying file.\n\t}\n\n\t// ReportWriter is a type of report writer that writes a summary of analysis reports.\n\tReportWriter interface {\n\t\tWriteReport(*SummaryReport) error\n\t}\n\n\t// A TemplateWriter is a type of writer that writes output according to a template.\n\tTemplateWriter struct {\n\t\tT *template.Template\n\t\tW io.Writer\n\t}\n\n\t// SilentError is returned in case the wrapped error is already\n\t// printed by the runner and should not be printed by its caller\n\tSilentError struct{ error }\n)\n\nconst (\n\tFileChangeAdded    FileChange = \"ADDED\"\n\tFileChangeDeleted  FileChange = \"DELETED\"\n\tFileChangeModified FileChange = \"MODIFIED\"\n)\n\n// NewSummaryReport returns a new SummaryReport.\nfunc NewSummaryReport(c *sqlclient.Client, dir migrate.Dir) *SummaryReport {\n\tsum := &SummaryReport{\n\t\tStart: time.Now(),\n\t\tEnv: struct {\n\t\t\tDriver string         `json:\"Driver,omitempty\"`\n\t\t\tURL    *sqlclient.URL `json:\"URL,omitempty\"`\n\t\t\tDir    string         `json:\"Dir,omitempty\"`\n\t\t}{\n\t\t\tDriver: c.Name,\n\t\t\tURL:    c.URL,\n\t\t},\n\t\tFiles: make([]*FileReport, 0),\n\t}\n\tif p, ok := dir.(interface{ Path() string }); ok {\n\t\tsum.Env.Dir = p.Path()\n\t}\n\treturn sum\n}\n\n// StepResult appends step result to the summary.\nfunc (r *SummaryReport) StepResult(name, text string, result *FileReport) {\n\tif result != nil {\n\t\tresult.End = time.Now()\n\t}\n\tr.Steps = append(r.Steps, &StepReport{\n\t\tName:   name,\n\t\tText:   text,\n\t\tResult: result,\n\t})\n}\n\n// StepError appends step error to the summary.\nfunc (r *SummaryReport) StepError(name, text string, err error) error {\n\tr.Steps = append(r.Steps, &StepReport{\n\t\tName:  name,\n\t\tText:  text,\n\t\tError: err.Error(),\n\t})\n\treturn err\n}\n\n// WriteSchema writes the current and desired schema to the summary.\nfunc (r *SummaryReport) WriteSchema(c *sqlclient.Client, diff *Changes) {\n\tif curr, err := c.MarshalSpec(diff.From); err == nil {\n\t\tr.Schema.Current = string(curr)\n\t}\n\tif desired, err := c.MarshalSpec(diff.To); err == nil {\n\t\tr.Schema.Desired = string(desired)\n\t}\n}\n\n// DiagnosticsCount returns the total number of diagnostics in the report.\nfunc (r *SummaryReport) DiagnosticsCount() int {\n\tvar n int\n\tfor _, f := range r.Files {\n\t\tfor _, r := range f.Reports {\n\t\t\tn += len(r.Diagnostics)\n\t\t}\n\t}\n\treturn n\n}\n\n// VersionStatuses returns statuses description of all versions (migration files).\nfunc (r *SummaryReport) VersionStatuses() string {\n\tvar ok, errs, warns int\n\tfor _, f := range r.Files {\n\t\tswitch {\n\t\tcase f.Error != \"\":\n\t\t\terrs++\n\t\tcase len(f.Reports) > 0:\n\t\t\twarns++\n\t\tdefault:\n\t\t\tok++\n\t\t}\n\t}\n\tparts := make([]string, 0, 3)\n\tfor _, s := range []struct {\n\t\tn int\n\t\ts string\n\t}{\n\t\t{ok, \"ok\"},\n\t\t{warns, \"with warnings\"},\n\t\t{errs, \"with errors\"},\n\t} {\n\t\tswitch {\n\t\tcase s.n == 0:\n\t\tcase s.n == 1 && len(parts) == 0:\n\t\t\tparts = append(parts, fmt.Sprintf(\"1 version %s\", s.s))\n\t\tcase s.n > 1 && len(parts) == 0:\n\t\t\tparts = append(parts, fmt.Sprintf(\"%d versions %s\", s.n, s.s))\n\t\tdefault:\n\t\t\tparts = append(parts, fmt.Sprintf(\"%d %s\", s.n, s.s))\n\t\t}\n\t}\n\treturn strings.Join(parts, \", \")\n}\n\n// TotalChanges returns the total number of changes that were analyzed.\nfunc (r *SummaryReport) TotalChanges() int {\n\tvar n int\n\tfor _, f := range r.Files {\n\t\tif f.File != nil {\n\t\t\tfor _, c := range f.File.Changes {\n\t\t\t\tn += len(c.Changes)\n\t\t\t}\n\t\t}\n\t}\n\treturn n\n}\n\n// NonFileReports returns reports that are not related to a file,\n// but more general, like non-linear/additive changes.\nfunc (r *SummaryReport) NonFileReports() (rs []*StepReport) {\n\tfor _, s := range r.Steps {\n\t\tif r1 := s.Result; r1 != nil && r1.File == nil && len(r1.Reports) > 0 {\n\t\t\trs = append(rs, s)\n\t\t}\n\t}\n\treturn rs\n}\n\n// NewFileReport returns a new FileReport.\nfunc NewFileReport(f *sqlcheck.File) *FileReport {\n\treturn &FileReport{Name: f.Name(), Text: string(f.Bytes()), Start: time.Now(), File: f}\n}\n\n// Line returns the line number from a position.\nfunc (f *FileReport) Line(pos int) int {\n\treturn strings.Count(f.Text[:pos], \"\\n\") + 1\n}\n\n// SuggestedFixes returns the list of suggested fixes for a specific report.\nfunc (f *FileReport) SuggestedFixes() []sqlcheck.SuggestedFix {\n\tvar fixes []sqlcheck.SuggestedFix\n\tfor _, r := range f.Reports {\n\t\t// Report-level fixes.\n\t\tfor _, x := range r.SuggestedFixes {\n\t\t\tif x.Message != \"\" {\n\t\t\t\tfixes = append(fixes, x)\n\t\t\t}\n\t\t}\n\t\t// Diagnostic-level fixes.\n\t\tfor _, d := range r.Diagnostics {\n\t\t\tfor _, x := range d.SuggestedFixes {\n\t\t\t\tif x.Message != \"\" {\n\t\t\t\t\tfixes = append(fixes, x)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn fixes\n}\n\n// WriteReport implements sqlcheck.ReportWriter.\nfunc (f *FileReport) WriteReport(r sqlcheck.Report) {\n\tf.Reports = append(f.Reports, r)\n}\n\n// WriteReport implements ReportWriter.\nfunc (w *TemplateWriter) WriteReport(r *SummaryReport) error {\n\treturn w.T.Execute(w.W, r)\n}\n\nfunc (err SilentError) Unwrap() error { return err.error }\n\nfunc nolintRules(f *sqlcheck.File) *skipRules {\n\ts := &skipRules{pos2rules: make(map[int][]string)}\n\tif l, ok := f.File.(*migrate.LocalFile); ok {\n\t\tds := l.Directive(\"nolint\")\n\t\t// A file directive without specific classes/codes\n\t\t// (e.g. atlas:nolint) ignores the entire file.\n\t\tif s.ignored = len(ds) == 1 && ds[0] == \"\"; s.ignored {\n\t\t\treturn s\n\t\t}\n\t\t// A file directive with specific classes/codes applies these\n\t\t// rules on all statements (e.g., atlas:nolint destructive).\n\t\tfor _, d := range ds {\n\t\t\tfor _, c := range f.Changes {\n\t\t\t\ts.pos2rules[c.Stmt.Pos] = append(s.pos2rules[c.Stmt.Pos], strings.Split(d, \" \")...)\n\t\t\t}\n\t\t}\n\t}\n\tfor _, c := range f.Changes {\n\t\t// A list of changes that were loaded in a batch (no statements per change).\n\t\tif c.Stmt != nil {\n\t\t\tfor _, d := range c.Stmt.Directive(\"nolint\") {\n\t\t\t\ts.pos2rules[c.Stmt.Pos] = append(s.pos2rules[c.Stmt.Pos], strings.Split(d, \" \")...)\n\t\t\t}\n\t\t}\n\t}\n\treturn s\n}\n\ntype skipRules struct {\n\tpos2rules map[int][]string // statement positions to rules\n\tignored   bool             // file is ignored. i.e., no analysis is performed\n\tskipped   bool             // if the last report was skipped by the rules\n}\n\nfunc (s *skipRules) reporterFor(rw sqlcheck.ReportWriter, az sqlcheck.Analyzer) sqlcheck.ReportWriter {\n\treturn sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\tvar (\n\t\t\tds     = make([]sqlcheck.Diagnostic, 0, len(r.Diagnostics))\n\t\t\taz, ok = az.(sqlcheck.NamedAnalyzer)\n\t\t)\n\t\tfor _, d := range r.Diagnostics {\n\t\t\tswitch rules := s.pos2rules[d.Pos]; {\n\t\t\tcase\n\t\t\t\t// A directive without specific classes/codes\n\t\t\t\t// (e.g. atlas:nolint) ignore all diagnostics.\n\t\t\t\tlen(rules) == 1 && rules[0] == \"\",\n\t\t\t\t// Match a specific code/diagnostic. e.g. atlas:nolint DS101.\n\t\t\t\tslices.Contains(rules, d.Code),\n\t\t\t\t// Skip the entire analyzer (class of changes).\n\t\t\t\tok && slices.Contains(rules, az.Name()):\n\t\t\tdefault:\n\t\t\t\tds = append(ds, d)\n\t\t\t}\n\t\t}\n\t\tif s.skipped = len(ds) == 0; !s.skipped {\n\t\t\trw.WriteReport(sqlcheck.Report{Text: r.Text, Diagnostics: ds})\n\t\t}\n\t})\n}\n\nfunc (d *DevLoader) stmts(_ context.Context, f migrate.File, _ bool) ([]*migrate.Stmt, error) {\n\tstmts, err := migrate.FileStmtDecls(d.Dev.Driver, f)\n\tif err != nil {\n\t\treturn nil, &FileError{File: f.Name(), Err: fmt.Errorf(\"scanning statements: %w\", err)}\n\t}\n\treturn stmts, nil\n}\n"
  },
  {
    "path": "cmd/atlas/internal/migratelint/lint_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage migratelint_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/migratelint\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t_ \"ariga.io/atlas/sql/sqlite\"\n\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGitChangeDetector(t *testing.T) {\n\t// Prepare environment.\n\troot := filepath.Join(t.TempDir(), t.Name(), strconv.FormatInt(time.Now().Unix(), 10))\n\tmdir := filepath.Join(root, \"migrations\")\n\trequire.NoError(t, os.MkdirAll(mdir, 0755))\n\tgit := func(args ...string) {\n\t\tout, err := exec.Command(\"git\", append([]string{\"-C\", root}, args...)...).CombinedOutput()\n\t\trequire.NoError(t, err, string(out))\n\t}\n\tgit(\"init\")\n\t// Config a fake Git user for the working directory.\n\tgit(\"config\", \"user.name\", \"a8m\")\n\tgit(\"config\", \"user.email\", \"a8m@atlasgo.io\")\n\trequire.NoError(t, os.WriteFile(filepath.Join(mdir, \"1_applied.sql\"), []byte(\"1_applied.sql\"), 0644))\n\trequire.NoError(t, os.WriteFile(filepath.Join(mdir, \"2_applied.sql\"), []byte(\"2_applied.sql\"), 0644))\n\tgit(\"add\", \".\")\n\tgit(\"commit\", \"-m\", \"applied migrations\")\n\tgit(\"checkout\", \"-b\", \"feature\")\n\trequire.NoError(t, os.WriteFile(filepath.Join(mdir, \"3_new.sql\"), []byte(\"3_new.sql\"), 0644))\n\trequire.NoError(t, os.WriteFile(filepath.Join(mdir, \"4_new.sql\"), []byte(\"4_new.sql\"), 0644))\n\tgit(\"add\", \".\")\n\tgit(\"commit\", \"-am\", \"new migrations\")\n\n\t// Test change detector.\n\tdir, err := migrate.NewLocalDir(mdir)\n\trequire.NoError(t, err)\n\tcs, err := migratelint.NewGitChangeDetector(dir, migratelint.WithWorkDir(root))\n\trequire.NoError(t, err)\n\tbase, feat, err := cs.DetectChanges(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, base, 2)\n\trequire.Len(t, feat, 2)\n\trequire.Equal(t, \"1_applied.sql\", base[0].Name())\n\trequire.Equal(t, \"2_applied.sql\", base[1].Name())\n\trequire.Equal(t, \"3_new.sql\", feat[0].Name())\n\trequire.Equal(t, \"4_new.sql\", feat[1].Name())\n\n\trequire.NoError(t, os.WriteFile(filepath.Join(mdir, \"5_new.sql\"), []byte(\"5_new.sql\"), 0644))\n\trequire.NoError(t, os.WriteFile(filepath.Join(mdir, \"6_new.sql\"), []byte(\"6_new.sql\"), 0644))\n\tgit(\"checkout\", \"-b\", \"feature-1\")\n\tgit(\"add\", \".\")\n\tgit(\"commit\", \"-am\", \"new migrations\")\n\tbase, feat, err = cs.DetectChanges(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, base, 2)\n\trequire.Len(t, feat, 4)\n\trequire.Equal(t, \"5_new.sql\", feat[2].Name())\n\trequire.Equal(t, \"6_new.sql\", feat[3].Name())\n\n\t// Compare feature and feature-1.\n\tcs, err = migratelint.NewGitChangeDetector(dir, migratelint.WithWorkDir(root), migratelint.WithBase(\"feature\"))\n\trequire.NoError(t, err)\n\tbase, feat, err = cs.DetectChanges(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, base, 4)\n\trequire.Len(t, feat, 2)\n\trequire.Equal(t, \"1_applied.sql\", base[0].Name())\n\trequire.Equal(t, \"2_applied.sql\", base[1].Name())\n\trequire.Equal(t, \"3_new.sql\", base[2].Name())\n\trequire.Equal(t, \"4_new.sql\", base[3].Name())\n\trequire.Equal(t, \"5_new.sql\", feat[0].Name())\n\trequire.Equal(t, \"6_new.sql\", feat[1].Name())\n}\n\nfunc TestDirChangeDetector(t *testing.T) {\n\tbase, head := &migrate.MemDir{}, &migrate.MemDir{}\n\trequire.NoError(t, base.WriteFile(\"1.sql\", []byte(\"create table t1 (id int)\")))\n\trequire.NoError(t, head.WriteFile(\"1.sql\", []byte(\"create table t1 (id int)\")))\n\trequire.NoError(t, base.WriteFile(\"2.sql\", []byte(\"create table t2 (id int)\")))\n\trequire.NoError(t, head.WriteFile(\"2.sql\", []byte(\"create table t2 (id int)\")))\n\n\tbaseF, newF, err := migratelint.DirChangeDetector{Base: base, Head: head}.DetectChanges(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, baseF, 2)\n\trequire.Empty(t, newF)\n\n\trequire.NoError(t, head.WriteFile(\"3.sql\", []byte(\"create table t3 (id int)\")))\n\tbaseF, newF, err = migratelint.DirChangeDetector{Base: base, Head: head}.DetectChanges(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, baseF, 2)\n\trequire.Len(t, newF, 1)\n}\n\nfunc TestLatestChanges(t *testing.T) {\n\tdir := &migrate.MemDir{}\n\trequire.NoError(t, dir.WriteFile(\"1.sql\", []byte(\"CREATE TABLE t1 (id INT)\")))\n\trequire.NoError(t, dir.WriteFile(\"2.sql\", []byte(\"CREATE TABLE t2 (id INT)\")))\n\tbase, feat, err := migratelint.LatestChanges(dir, 0).DetectChanges(context.Background())\n\trequire.NoError(t, err)\n\tfiles, err := dir.Files()\n\trequire.NoError(t, err)\n\trequire.Equal(t, files, base)\n\trequire.Empty(t, feat)\n\n\tbase, feat, err = migratelint.LatestChanges(dir, 2).DetectChanges(context.Background())\n\trequire.NoError(t, err)\n\trequire.Empty(t, base)\n\trequire.Equal(t, files, feat)\n\n\tbase, feat, err = migratelint.LatestChanges(dir, -1).DetectChanges(context.Background())\n\trequire.NoError(t, err)\n\trequire.Empty(t, base)\n\trequire.Equal(t, files, feat)\n\n\tbase, feat, err = migratelint.LatestChanges(dir, 1).DetectChanges(context.Background())\n\trequire.NoError(t, err)\n\trequire.Equal(t, files[:1], base)\n\trequire.Equal(t, files[1:], feat)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/myparse/myparse_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage myparse\n\nimport (\n\t\"errors\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// Parser for fixing linting changes.\ntype FileParser struct{}\n\n// FixChange fixes the changes according to the given statement.\nfunc (*FileParser) FixChange(migrate.Driver, string, schema.Changes) (schema.Changes, error) {\n\treturn nil, errors.New(\"unimplemented\")\n}\n\n// ColumnFilledBefore checks if the column was filled with values before the given position in the file.\nfunc (*FileParser) ColumnFilledBefore([]*migrate.Stmt, *schema.Table, *schema.Column, int) (bool, error) {\n\treturn false, errors.New(\"unimplemented\")\n}\n\n// CreateViewAfter checks if a view was created after the position with the given name to a table.\nfunc (*FileParser) CreateViewAfter([]*migrate.Stmt, string, string, int) (bool, error) {\n\treturn false, errors.New(\"unimplemented\")\n}\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/parseutil/parseutil.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Package parseutil exposes shared functions used by the different parsers.\npackage parseutil\n\nimport (\n\t\"slices\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// Rename describes rename of a resource.\ntype Rename struct {\n\tFrom, To string\n}\n\n// RenameColumn patches DROP/ADD column commands to RENAME.\nfunc RenameColumn(modify *schema.ModifyTable, r *Rename) {\n\tchanges := schema.Changes(modify.Changes)\n\tswitch i, j := changes.IndexDropColumn(r.From), changes.IndexAddColumn(r.To); {\n\tcase j == -1:\n\t// Rename column.\n\tcase i != -1:\n\t\tchanges[max(i, j)] = &schema.RenameColumn{\n\t\t\tFrom: changes[i].(*schema.DropColumn).C,\n\t\t\tTo:   changes[j].(*schema.AddColumn).C,\n\t\t}\n\t\tchanges.RemoveIndex(min(i, j))\n\t// Rename column and add the previous name back.\n\tdefault:\n\t\tif i = changes.IndexModifyColumn(r.From); i == -1 {\n\t\t\t// ADD COLUMN must come after the RENAME.\n\t\t\treturn\n\t\t}\n\t\tmodify := changes[i].(*schema.ModifyColumn)\n\t\tchanges[min(i, j)] = &schema.RenameColumn{\n\t\t\tFrom: modify.From,\n\t\t\tTo:   changes[j].(*schema.AddColumn).C,\n\t\t}\n\t\tchanges[max(i, j)] = &schema.AddColumn{\n\t\t\tC: modify.To,\n\t\t}\n\t}\n\tmodify.Changes = changes\n}\n\n// RenameIndex patches DROP/ADD index commands to RENAME.\nfunc RenameIndex(modify *schema.ModifyTable, r *Rename) {\n\tchanges := schema.Changes(modify.Changes)\n\ti := changes.IndexDropIndex(r.From)\n\tj := changes.IndexAddIndex(r.To)\n\tif i != -1 && j != -1 {\n\t\tchanges[max(i, j)] = &schema.RenameIndex{\n\t\t\tFrom: changes[i].(*schema.DropIndex).I,\n\t\t\tTo:   changes[j].(*schema.AddIndex).I,\n\t\t}\n\t\tchanges.RemoveIndex(min(i, j))\n\t\tmodify.Changes = changes\n\t}\n}\n\n// RenameTable patches DROP/ADD table commands to RENAME.\nfunc RenameTable(changes schema.Changes, r *Rename) schema.Changes {\n\ti := changes.LastIndexDropTable(r.From)\n\tj := changes.LastIndexAddTable(r.To)\n\tif i != -1 && j != -1 {\n\t\tchanges[max(i, j)] = &schema.RenameTable{\n\t\t\tFrom: changes[i].(*schema.DropTable).T,\n\t\t\tTo:   changes[j].(*schema.AddTable).T,\n\t\t}\n\t\tchanges.RemoveIndex(min(i, j))\n\t}\n\treturn changes\n}\n\n// MatchStmtBefore reports if the file contains any statement that matches the predicate before the given position.\nfunc MatchStmtBefore(stmts []*migrate.Stmt, pos int, p func(*migrate.Stmt) (bool, error)) (bool, error) {\n\ti := slices.IndexFunc(stmts, func(s *migrate.Stmt) bool {\n\t\treturn s.Pos >= pos\n\t})\n\tif i != -1 {\n\t\tstmts = stmts[:i]\n\t}\n\tfor _, s := range stmts {\n\t\tm, err := p(s)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif m {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\treturn false, nil\n}\n\n// MatchStmtAfter reports if the file contains any statement that matches the predicate after the given position.\nfunc MatchStmtAfter(stmts []*migrate.Stmt, pos int, p func(*migrate.Stmt) (bool, error)) (bool, error) {\n\ti := slices.IndexFunc(stmts, func(s *migrate.Stmt) bool {\n\t\treturn s.Pos > pos\n\t})\n\tif i == -1 {\n\t\treturn false, nil\n\t}\n\tstmts = stmts[i:]\n\tfor _, s := range stmts {\n\t\tm, err := p(s)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif m {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\treturn false, nil\n}\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/pgparse/pgparse_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage pgparse\n\nimport (\n\t\"errors\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\ntype Parser struct{}\n\nfunc (*Parser) ColumnFilledBefore([]*migrate.Stmt, *schema.Table, *schema.Column, int) (bool, error) {\n\treturn false, errors.New(\"unimplemented\")\n}\n\nfunc (*Parser) CreateViewAfter([]*migrate.Stmt, string, string, int) (bool, error) {\n\treturn false, errors.New(\"unimplemented\")\n}\n\nfunc (*Parser) FixChange(_ migrate.Driver, _ string, changes schema.Changes) (schema.Changes, error) {\n\treturn changes, nil // Unimplemented.\n}\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqliteparse/Lexer.g4",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2020 by Martin Mirchev\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and\n * associated documentation files (the \"Software\"), to deal in the Software without restriction,\n * including without limitation the rights to use, copy, modify, merge, publish, distribute,\n * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or\n * substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\n * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * Project : sqlite-parser; an ANTLR4 grammar for SQLite https://github.com/bkiers/sqlite-parser\n * Developed by : Bart Kiers, bart@big-o.nl\n */\n\n// $antlr-format alignTrailingComments on, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments off, useTab off\n// $antlr-format allowShortRulesOnASingleLine on, alignSemicolons ownLine\n\nlexer grammar Lexer;\n\noptions { caseInsensitive = true; }\n\nSCOL:      ';';\nDOT:       '.';\nOPEN_PAR:  '(';\nCLOSE_PAR: ')';\nCOMMA:     ',';\nASSIGN:    '=';\nSTAR:      '*';\nPLUS:      '+';\nMINUS:     '-';\nTILDE:     '~';\nPIPE2:     '||';\nDIV:       '/';\nMOD:       '%';\nLT2:       '<<';\nGT2:       '>>';\nAMP:       '&';\nPIPE:      '|';\nLT:        '<';\nLT_EQ:     '<=';\nGT:        '>';\nGT_EQ:     '>=';\nEQ:        '==';\nNOT_EQ1:   '!=';\nNOT_EQ2:   '<>';\n\n// http://www.sqlite.org/lang_keywords.html\nABORT_:             'ABORT';\nACTION_:            'ACTION';\nADD_:               'ADD';\nAFTER_:             'AFTER';\nALL_:               'ALL';\nALTER_:             'ALTER';\nANALYZE_:           'ANALYZE';\nAND_:               'AND';\nAS_:                'AS';\nASC_:               'ASC';\nATTACH_:            'ATTACH';\nAUTOINCREMENT_:     'AUTOINCREMENT';\nBEFORE_:            'BEFORE';\nBEGIN_:             'BEGIN';\nBETWEEN_:           'BETWEEN';\nBY_:                'BY';\nCASCADE_:           'CASCADE';\nCASE_:              'CASE';\nCAST_:              'CAST';\nCHECK_:             'CHECK';\nCOLLATE_:           'COLLATE';\nCOLUMN_:            'COLUMN';\nCOMMIT_:            'COMMIT';\nCONFLICT_:          'CONFLICT';\nCONSTRAINT_:        'CONSTRAINT';\nCREATE_:            'CREATE';\nCROSS_:             'CROSS';\nCURRENT_DATE_:      'CURRENT_DATE';\nCURRENT_TIME_:      'CURRENT_TIME';\nCURRENT_TIMESTAMP_: 'CURRENT_TIMESTAMP';\nDATABASE_:          'DATABASE';\nDEFAULT_:           'DEFAULT';\nDEFERRABLE_:        'DEFERRABLE';\nDEFERRED_:          'DEFERRED';\nDELETE_:            'DELETE';\nDESC_:              'DESC';\nDETACH_:            'DETACH';\nDISTINCT_:          'DISTINCT';\nDROP_:              'DROP';\nEACH_:              'EACH';\nELSE_:              'ELSE';\nEND_:               'END';\nESCAPE_:            'ESCAPE';\nEXCEPT_:            'EXCEPT';\nEXCLUSIVE_:         'EXCLUSIVE';\nEXISTS_:            'EXISTS';\nEXPLAIN_:           'EXPLAIN';\nFAIL_:              'FAIL';\nFOR_:               'FOR';\nFOREIGN_:           'FOREIGN';\nFROM_:              'FROM';\nFULL_:              'FULL';\nGLOB_:              'GLOB';\nGROUP_:             'GROUP';\nHAVING_:            'HAVING';\nIF_:                'IF';\nIGNORE_:            'IGNORE';\nIMMEDIATE_:         'IMMEDIATE';\nIN_:                'IN';\nINDEX_:             'INDEX';\nINDEXED_:           'INDEXED';\nINITIALLY_:         'INITIALLY';\nINNER_:             'INNER';\nINSERT_:            'INSERT';\nINSTEAD_:           'INSTEAD';\nINTERSECT_:         'INTERSECT';\nINTO_:              'INTO';\nIS_:                'IS';\nISNULL_:            'ISNULL';\nJOIN_:              'JOIN';\nKEY_:               'KEY';\nLEFT_:              'LEFT';\nLIKE_:              'LIKE';\nLIMIT_:             'LIMIT';\nMATCH_:             'MATCH';\nNATURAL_:           'NATURAL';\nNO_:                'NO';\nNOT_:               'NOT';\nNOTNULL_:           'NOTNULL';\nNULL_:              'NULL';\nOF_:                'OF';\nOFFSET_:            'OFFSET';\nON_:                'ON';\nOR_:                'OR';\nORDER_:             'ORDER';\nOUTER_:             'OUTER';\nPLAN_:              'PLAN';\nPRAGMA_:            'PRAGMA';\nPRIMARY_:           'PRIMARY';\nQUERY_:             'QUERY';\nRAISE_:             'RAISE';\nRECURSIVE_:         'RECURSIVE';\nREFERENCES_:        'REFERENCES';\nREGEXP_:            'REGEXP';\nREINDEX_:           'REINDEX';\nRELEASE_:           'RELEASE';\nRENAME_:            'RENAME';\nREPLACE_:           'REPLACE';\nRESTRICT_:          'RESTRICT';\nRETURNING_:         'RETURNING';\nRIGHT_:             'RIGHT';\nROLLBACK_:          'ROLLBACK';\nROW_:               'ROW';\nROWS_:              'ROWS';\nSAVEPOINT_:         'SAVEPOINT';\nSELECT_:            'SELECT';\nSET_:               'SET';\nTABLE_:             'TABLE';\nTEMP_:              'TEMP';\nTEMPORARY_:         'TEMPORARY';\nTHEN_:              'THEN';\nTO_:                'TO';\nTRANSACTION_:       'TRANSACTION';\nTRIGGER_:           'TRIGGER';\nUNION_:             'UNION';\nUNIQUE_:            'UNIQUE';\nUPDATE_:            'UPDATE';\nUSING_:             'USING';\nVACUUM_:            'VACUUM';\nVALUES_:            'VALUES';\nVIEW_:              'VIEW';\nVIRTUAL_:           'VIRTUAL';\nWHEN_:              'WHEN';\nWHERE_:             'WHERE';\nWITH_:              'WITH';\nWITHOUT_:           'WITHOUT';\nFIRST_VALUE_:       'FIRST_VALUE';\nOVER_:              'OVER';\nPARTITION_:         'PARTITION';\nRANGE_:             'RANGE';\nPRECEDING_:         'PRECEDING';\nUNBOUNDED_:         'UNBOUNDED';\nCURRENT_:           'CURRENT';\nFOLLOWING_:         'FOLLOWING';\nCUME_DIST_:         'CUME_DIST';\nDENSE_RANK_:        'DENSE_RANK';\nLAG_:               'LAG';\nLAST_VALUE_:        'LAST_VALUE';\nLEAD_:              'LEAD';\nNTH_VALUE_:         'NTH_VALUE';\nNTILE_:             'NTILE';\nPERCENT_RANK_:      'PERCENT_RANK';\nRANK_:              'RANK';\nROW_NUMBER_:        'ROW_NUMBER';\nGENERATED_:         'GENERATED';\nALWAYS_:            'ALWAYS';\nSTORED_:            'STORED';\nTRUE_:              'TRUE';\nFALSE_:             'FALSE';\nWINDOW_:            'WINDOW';\nNULLS_:             'NULLS';\nFIRST_:             'FIRST';\nLAST_:              'LAST';\nFILTER_:            'FILTER';\nGROUPS_:            'GROUPS';\nEXCLUDE_:           'EXCLUDE';\nTIES_:              'TIES';\nOTHERS_:            'OTHERS';\nDO_:                'DO';\nNOTHING_:           'NOTHING';\n\nIDENTIFIER:\n    '\"' (~'\"' | '\"\"')* '\"'\n    | '`' (~'`' | '``')* '`'\n    | '[' ~']'* ']'\n    | [A-Z_] [A-Z_0-9]*\n; // TODO check: needs more chars in set\n\nNUMERIC_LITERAL: ((DIGIT+ ('.' DIGIT*)?) | ('.' DIGIT+)) ('E' [-+]? DIGIT+)? | '0x' HEX_DIGIT+;\n\nBIND_PARAMETER: '?' DIGIT* | [:@$] IDENTIFIER;\n\nSTRING_LITERAL: '\\'' ( ~'\\'' | '\\'\\'')* '\\'';\n\nBLOB_LITERAL: 'X' STRING_LITERAL;\n\nSINGLE_LINE_COMMENT: '--' ~[\\r\\n]* (('\\r'? '\\n') | EOF) -> channel(HIDDEN);\n\nMULTILINE_COMMENT: '/*' .*? '*/' -> channel(HIDDEN);\n\nSPACES: [ \\u000B\\t\\r\\n] -> channel(HIDDEN);\n\nUNEXPECTED_CHAR: .;\n\nfragment HEX_DIGIT: [0-9A-F];\nfragment DIGIT:     [0-9];\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqliteparse/Parser.g4",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 by Bart Kiers\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and\n * associated documentation files (the \"Software\"), to deal in the Software without restriction,\n * including without limitation the rights to use, copy, modify, merge, publish, distribute,\n * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or\n * substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT\n * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n *\n * Project : sqlite-parser; an ANTLR4 grammar for SQLite https://github.com/bkiers/sqlite-parser\n * Developed by:\n *     Bart Kiers, bart@big-o.nl\n *     Martin Mirchev, marti_2203@abv.bg\n *     Mike Lische, mike@lischke-online.de\n */\n\n// $antlr-format alignTrailingComments on, columnLimit 130, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments off\n// $antlr-format useTab off, allowShortRulesOnASingleLine off, allowShortBlocksOnASingleLine on, alignSemicolons ownLine\n\nparser grammar Parser;\n\noptions {\n    tokenVocab = Lexer;\n}\n\nparse: (sql_stmt_list)* EOF\n;\n\nsql_stmt_list:\n    SCOL* sql_stmt (SCOL+ sql_stmt)* SCOL*\n;\n\nsql_stmt: (EXPLAIN_ (QUERY_ PLAN_)?)? (\n        alter_table_stmt\n        | analyze_stmt\n        | attach_stmt\n        | begin_stmt\n        | commit_stmt\n        | create_index_stmt\n        | create_table_stmt\n        | create_trigger_stmt\n        | create_view_stmt\n        | create_virtual_table_stmt\n        | delete_stmt\n        | delete_stmt_limited\n        | detach_stmt\n        | drop_stmt\n        | insert_stmt\n        | pragma_stmt\n        | reindex_stmt\n        | release_stmt\n        | rollback_stmt\n        | savepoint_stmt\n        | select_stmt\n        | update_stmt\n        | update_stmt_limited\n        | vacuum_stmt\n    )\n;\n\nalter_table_stmt:\n    ALTER_ TABLE_ (schema_name DOT)? table_name (\n        RENAME_ (\n            TO_ new_table_name = table_name\n            | COLUMN_? old_column_name = column_name TO_ new_column_name = column_name\n        )\n        | ADD_ COLUMN_? column_def\n        | DROP_ COLUMN_? column_name\n    )\n;\n\nanalyze_stmt:\n    ANALYZE_ (schema_name | (schema_name DOT)? table_or_index_name)?\n;\n\nattach_stmt:\n    ATTACH_ DATABASE_? expr AS_ schema_name\n;\n\nbegin_stmt:\n    BEGIN_ (DEFERRED_ | IMMEDIATE_ | EXCLUSIVE_)? (\n        TRANSACTION_ transaction_name?\n    )?\n;\n\ncommit_stmt: (COMMIT_ | END_) TRANSACTION_?\n;\n\nrollback_stmt:\n    ROLLBACK_ TRANSACTION_? (TO_ SAVEPOINT_? savepoint_name)?\n;\n\nsavepoint_stmt:\n    SAVEPOINT_ savepoint_name\n;\n\nrelease_stmt:\n    RELEASE_ SAVEPOINT_? savepoint_name\n;\n\ncreate_index_stmt:\n    CREATE_ UNIQUE_? INDEX_ (IF_ NOT_ EXISTS_)? (schema_name DOT)? index_name ON_ table_name OPEN_PAR\n        indexed_column (COMMA indexed_column)* CLOSE_PAR (WHERE_ expr)?\n;\n\nindexed_column: (column_name | expr) (COLLATE_ collation_name)? asc_desc?\n;\n\ncreate_table_stmt:\n    CREATE_ (TEMP_ | TEMPORARY_)? TABLE_ (IF_ NOT_ EXISTS_)? (\n        schema_name DOT\n    )? table_name (\n        OPEN_PAR column_def (COMMA column_def)*? (COMMA table_constraint)* CLOSE_PAR (\n            WITHOUT_ row_ROW_ID = IDENTIFIER\n        )?\n        | AS_ select_stmt\n    )\n;\n\ncolumn_def:\n    column_name type_name? column_constraint*\n;\n\ntype_name:\n    name+? (\n        OPEN_PAR signed_number CLOSE_PAR\n        | OPEN_PAR signed_number COMMA signed_number CLOSE_PAR\n    )?\n;\n\ncolumn_constraint: (CONSTRAINT_ name)? (\n        (PRIMARY_ KEY_ asc_desc? conflict_clause? AUTOINCREMENT_?)\n        | (NOT_ NULL_ | UNIQUE_) conflict_clause?\n        | CHECK_ OPEN_PAR expr CLOSE_PAR\n        | DEFAULT_ (signed_number | literal_value | OPEN_PAR expr CLOSE_PAR)\n        | COLLATE_ collation_name\n        | foreign_key_clause\n        | (GENERATED_ ALWAYS_)? AS_ OPEN_PAR expr CLOSE_PAR (\n            STORED_\n            | VIRTUAL_\n        )?\n    )\n;\n\nsigned_number: (PLUS | MINUS)? NUMERIC_LITERAL\n;\n\ntable_constraint: (CONSTRAINT_ name)? (\n        (PRIMARY_ KEY_ | UNIQUE_) OPEN_PAR indexed_column (\n            COMMA indexed_column\n        )* CLOSE_PAR conflict_clause?\n        | CHECK_ OPEN_PAR expr CLOSE_PAR\n        | FOREIGN_ KEY_ OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR foreign_key_clause\n    )\n;\n\nforeign_key_clause:\n    REFERENCES_ foreign_table (\n        OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR\n    )? (\n        ON_ (DELETE_ | UPDATE_) (\n            SET_ (NULL_ | DEFAULT_)\n            | CASCADE_\n            | RESTRICT_\n            | NO_ ACTION_\n        )\n        | MATCH_ name\n    )* (NOT_? DEFERRABLE_ (INITIALLY_ (DEFERRED_ | IMMEDIATE_))?)?\n;\n\nconflict_clause:\n    ON_ CONFLICT_ (\n        ROLLBACK_\n        | ABORT_\n        | FAIL_\n        | IGNORE_\n        | REPLACE_\n    )\n;\n\ncreate_trigger_stmt:\n    CREATE_ (TEMP_ | TEMPORARY_)? TRIGGER_ (IF_ NOT_ EXISTS_)? (\n        schema_name DOT\n    )? trigger_name (BEFORE_ | AFTER_ | INSTEAD_ OF_)? (\n        DELETE_\n        | INSERT_\n        | UPDATE_ (OF_ column_name ( COMMA column_name)*)?\n    ) ON_ table_name (FOR_ EACH_ ROW_)? (WHEN_ expr)? BEGIN_ (\n        (update_stmt | insert_stmt | delete_stmt | select_stmt) SCOL\n    )+ END_\n;\n\ncreate_view_stmt:\n    CREATE_ (TEMP_ | TEMPORARY_)? VIEW_ (IF_ NOT_ EXISTS_)? (\n        schema_name DOT\n    )? view_name (OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR)? AS_ select_stmt\n;\n\ncreate_virtual_table_stmt:\n    CREATE_ VIRTUAL_ TABLE_ (IF_ NOT_ EXISTS_)? (schema_name DOT)? table_name USING_ module_name (\n        OPEN_PAR module_argument (COMMA module_argument)* CLOSE_PAR\n    )?\n;\n\nwith_clause:\n    WITH_ RECURSIVE_? cte_table_name AS_ OPEN_PAR select_stmt CLOSE_PAR (\n        COMMA cte_table_name AS_ OPEN_PAR select_stmt CLOSE_PAR\n    )*\n;\n\ncte_table_name:\n    table_name (OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR)?\n;\n\nrecursive_cte:\n    cte_table_name AS_ OPEN_PAR initial_select UNION_ ALL_? recursive_select CLOSE_PAR\n;\n\ncommon_table_expression:\n    table_name (OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR)? AS_ OPEN_PAR select_stmt CLOSE_PAR\n;\n\ndelete_stmt:\n    with_clause? DELETE_ FROM_ qualified_table_name (WHERE_ expr)? returning_clause?\n;\n\ndelete_stmt_limited:\n    with_clause? DELETE_ FROM_ qualified_table_name (WHERE_ expr)? returning_clause? (\n        order_by_stmt? limit_stmt\n    )?\n;\n\ndetach_stmt:\n    DETACH_ DATABASE_? schema_name\n;\n\ndrop_stmt:\n    DROP_ object = (INDEX_ | TABLE_ | TRIGGER_ | VIEW_) (\n        IF_ EXISTS_\n    )? (schema_name DOT)? any_name\n;\n\n/*\n SQLite understands the following binary operators, in order from highest to lowest precedence:\n    ||\n    * / %\n    + -\n    << >> & |\n    < <= > >=\n    = == != <> IS IS NOT IN LIKE GLOB MATCH REGEXP\n    AND\n    OR\n */\nexpr:\n    literal_value\n    | BIND_PARAMETER\n    | ((schema_name DOT)? table_name DOT)? column_name\n    | unary_operator expr\n    | expr PIPE2 expr\n    | expr ( STAR | DIV | MOD) expr\n    | expr ( PLUS | MINUS) expr\n    | expr ( LT2 | GT2 | AMP | PIPE) expr\n    | expr ( LT | LT_EQ | GT | GT_EQ) expr\n    | expr (\n        ASSIGN\n        | EQ\n        | NOT_EQ1\n        | NOT_EQ2\n        | IS_\n        | IS_ NOT_\n        | IN_\n        | LIKE_\n        | GLOB_\n        | MATCH_\n        | REGEXP_\n    ) expr\n    | expr AND_ expr\n    | expr OR_ expr\n    | function_name OPEN_PAR ((DISTINCT_? expr ( COMMA expr)*) | STAR)? CLOSE_PAR filter_clause? over_clause?\n    | OPEN_PAR expr (COMMA expr)* CLOSE_PAR\n    | CAST_ OPEN_PAR expr AS_ type_name CLOSE_PAR\n    | expr COLLATE_ collation_name\n    | expr NOT_? (LIKE_ | GLOB_ | REGEXP_ | MATCH_) expr (\n        ESCAPE_ expr\n    )?\n    | expr ( ISNULL_ | NOTNULL_ | NOT_ NULL_)\n    | expr IS_ NOT_? expr\n    | expr NOT_? BETWEEN_ expr AND_ expr\n    | expr NOT_? IN_ (\n        OPEN_PAR (select_stmt | expr ( COMMA expr)*)? CLOSE_PAR\n        | ( schema_name DOT)? table_name\n        | (schema_name DOT)? table_function_name OPEN_PAR (expr (COMMA expr)*)? CLOSE_PAR\n    )\n    | ((NOT_)? EXISTS_)? OPEN_PAR select_stmt CLOSE_PAR\n    | CASE_ expr? (WHEN_ expr THEN_ expr)+ (ELSE_ expr)? END_\n    | raise_function\n;\n\nraise_function:\n    RAISE_ OPEN_PAR (\n        IGNORE_\n        | (ROLLBACK_ | ABORT_ | FAIL_) COMMA error_message\n    ) CLOSE_PAR\n;\n\nliteral_value:\n    NUMERIC_LITERAL\n    | STRING_LITERAL\n    | BLOB_LITERAL\n    | NULL_\n    | TRUE_\n    | FALSE_\n    | CURRENT_TIME_\n    | CURRENT_DATE_\n    | CURRENT_TIMESTAMP_\n;\n\ninsert_stmt:\n    with_clause? (\n        INSERT_\n        | REPLACE_\n        | INSERT_ OR_ (\n            REPLACE_\n            | ROLLBACK_\n            | ABORT_\n            | FAIL_\n            | IGNORE_\n        )\n    ) INTO_ (schema_name DOT)? table_name (AS_ table_alias)? (\n        OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR\n    )? (\n        (\n            (\n                VALUES_ OPEN_PAR expr (COMMA expr)* CLOSE_PAR (\n                    COMMA OPEN_PAR expr ( COMMA expr)* CLOSE_PAR\n                )*\n                | select_stmt\n            ) upsert_clause?\n        )\n        | DEFAULT_ VALUES_\n    ) returning_clause?\n;\n\nreturning_clause:\n    RETURNING_ result_column (COMMA result_column)*\n;\n\nupsert_clause:\n    ON_ CONFLICT_ (\n        OPEN_PAR indexed_column (COMMA indexed_column)* CLOSE_PAR (WHERE_ expr)?\n    )? DO_ (\n        NOTHING_\n        | UPDATE_ SET_ (\n            (column_name | column_name_list) ASSIGN expr (\n                COMMA (column_name | column_name_list) ASSIGN expr\n            )* (WHERE_ expr)?\n        )\n    )\n;\n\npragma_stmt:\n    PRAGMA_ (schema_name DOT)? pragma_name (\n        ASSIGN pragma_value\n        | OPEN_PAR pragma_value CLOSE_PAR\n    )?\n;\n\npragma_value:\n    signed_number\n    | name\n    | STRING_LITERAL\n;\n\nreindex_stmt:\n    REINDEX_ (collation_name | (schema_name DOT)? (table_name | index_name))?\n;\n\nselect_stmt:\n    common_table_stmt? select_core (compound_operator select_core)* order_by_stmt? limit_stmt?\n;\n\njoin_clause:\n    table_or_subquery (join_operator table_or_subquery join_constraint?)*\n;\n\nselect_core:\n    (\n        SELECT_ (DISTINCT_ | ALL_)? result_column (COMMA result_column)* (\n            FROM_ (table_or_subquery (COMMA table_or_subquery)* | join_clause)\n        )? (WHERE_ expr)? (GROUP_ BY_ expr (COMMA expr)* (HAVING_ expr)?)? (\n            WINDOW_ window_name AS_ window_defn (\n                COMMA window_name AS_ window_defn\n            )*\n        )?\n    )\n    | VALUES_ OPEN_PAR expr (COMMA expr)* CLOSE_PAR (\n        COMMA OPEN_PAR expr ( COMMA expr)* CLOSE_PAR\n    )*\n;\n\nfactored_select_stmt:\n    select_stmt\n;\n\nsimple_select_stmt:\n    common_table_stmt? select_core order_by_stmt? limit_stmt?\n;\n\ncompound_select_stmt:\n    common_table_stmt? select_core (\n        (UNION_ ALL_? | INTERSECT_ | EXCEPT_) select_core\n    )+ order_by_stmt? limit_stmt?\n;\n\ntable_or_subquery: (\n        (schema_name DOT)? table_name (AS_? table_alias)? (\n            INDEXED_ BY_ index_name\n            | NOT_ INDEXED_\n        )?\n    )\n    | (schema_name DOT)? table_function_name OPEN_PAR expr (COMMA expr)* CLOSE_PAR (\n        AS_? table_alias\n    )?\n    | OPEN_PAR (table_or_subquery (COMMA table_or_subquery)* | join_clause) CLOSE_PAR\n    | OPEN_PAR select_stmt CLOSE_PAR (AS_? table_alias)?\n;\n\nresult_column:\n    STAR\n    | table_name DOT STAR\n    | expr ( AS_? column_alias)?\n;\n\njoin_operator:\n    COMMA\n    | NATURAL_? (LEFT_ OUTER_? | INNER_ | CROSS_)? JOIN_\n;\n\njoin_constraint:\n    ON_ expr\n    | USING_ OPEN_PAR column_name ( COMMA column_name)* CLOSE_PAR\n;\n\ncompound_operator:\n    UNION_ ALL_?\n    | INTERSECT_\n    | EXCEPT_\n;\n\nupdate_stmt:\n    with_clause? UPDATE_ (\n        OR_ (ROLLBACK_ | ABORT_ | REPLACE_ | FAIL_ | IGNORE_)\n    )? qualified_table_name SET_ assignment_list (\n        FROM_ (table_or_subquery (COMMA table_or_subquery)* | join_clause)\n    )? (WHERE_ where = expr)? returning_clause?\n;\n\nassignment_list:\n    assignment\n    (COMMA assignment)*\n;\n\nassignment:\n    (column_name | column_name_list) ASSIGN expr\n;\n\ncolumn_name_list:\n    OPEN_PAR column_name (COMMA column_name)* CLOSE_PAR\n;\n\nupdate_stmt_limited:\n    with_clause? UPDATE_ (\n        OR_ (ROLLBACK_ | ABORT_ | REPLACE_ | FAIL_ | IGNORE_)\n    )? qualified_table_name SET_ (column_name | column_name_list) ASSIGN expr (\n        COMMA (column_name | column_name_list) ASSIGN expr\n    )* (WHERE_ expr)? returning_clause? (order_by_stmt? limit_stmt)?\n;\n\nqualified_table_name: (schema_name DOT)? table_name (AS_ alias)? (\n        INDEXED_ BY_ index_name\n        | NOT_ INDEXED_\n    )?\n;\n\nvacuum_stmt:\n    VACUUM_ schema_name? (INTO_ filename)?\n;\n\nfilter_clause:\n    FILTER_ OPEN_PAR WHERE_ expr CLOSE_PAR\n;\n\nwindow_defn:\n    OPEN_PAR base_window_name? (PARTITION_ BY_ expr (COMMA expr)*)? (\n        ORDER_ BY_ ordering_term (COMMA ordering_term)*\n    ) frame_spec? CLOSE_PAR\n;\n\nover_clause:\n    OVER_ (\n        window_name\n        | OPEN_PAR base_window_name? (PARTITION_ BY_ expr (COMMA expr)*)? (\n            ORDER_ BY_ ordering_term (COMMA ordering_term)*\n        )? frame_spec? CLOSE_PAR\n    )\n;\n\nframe_spec:\n    frame_clause (\n        EXCLUDE_ (NO_ OTHERS_)\n        | CURRENT_ ROW_\n        | GROUP_\n        | TIES_\n    )?\n;\n\nframe_clause: (RANGE_ | ROWS_ | GROUPS_) (\n        frame_single\n        | BETWEEN_ frame_left AND_ frame_right\n    )\n;\n\nsimple_function_invocation:\n    simple_func OPEN_PAR (expr (COMMA expr)* | STAR) CLOSE_PAR\n;\n\naggregate_function_invocation:\n    aggregate_func OPEN_PAR (DISTINCT_? expr (COMMA expr)* | STAR)? CLOSE_PAR filter_clause?\n;\n\nwindow_function_invocation:\n    window_function OPEN_PAR (expr (COMMA expr)* | STAR)? CLOSE_PAR filter_clause? OVER_ (\n        window_defn\n        | window_name\n    )\n;\n\ncommon_table_stmt: //additional structures\n    WITH_ RECURSIVE_? common_table_expression (COMMA common_table_expression)*\n;\n\norder_by_stmt:\n    ORDER_ BY_ ordering_term (COMMA ordering_term)*\n;\n\nlimit_stmt:\n    LIMIT_ expr ((OFFSET_ | COMMA) expr)?\n;\n\nordering_term:\n    expr (COLLATE_ collation_name)? asc_desc? (NULLS_ (FIRST_ | LAST_))?\n;\n\nasc_desc:\n    ASC_\n    | DESC_\n;\n\nframe_left:\n    expr PRECEDING_\n    | expr FOLLOWING_\n    | CURRENT_ ROW_\n    | UNBOUNDED_ PRECEDING_\n;\n\nframe_right:\n    expr PRECEDING_\n    | expr FOLLOWING_\n    | CURRENT_ ROW_\n    | UNBOUNDED_ FOLLOWING_\n;\n\nframe_single:\n    expr PRECEDING_\n    | UNBOUNDED_ PRECEDING_\n    | CURRENT_ ROW_\n;\n\n// unknown\n\nwindow_function:\n    (FIRST_VALUE_ | LAST_VALUE_) OPEN_PAR expr CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc frame_clause\n        ? CLOSE_PAR\n    | (CUME_DIST_ | PERCENT_RANK_) OPEN_PAR CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr? CLOSE_PAR\n    | (DENSE_RANK_ | RANK_ | ROW_NUMBER_) OPEN_PAR CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc\n        CLOSE_PAR\n    | (LAG_ | LEAD_) OPEN_PAR expr offset? default_value? CLOSE_PAR OVER_ OPEN_PAR partition_by?\n        order_by_expr_asc_desc CLOSE_PAR\n    | NTH_VALUE_ OPEN_PAR expr COMMA signed_number CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc\n        frame_clause? CLOSE_PAR\n    | NTILE_ OPEN_PAR expr CLOSE_PAR OVER_ OPEN_PAR partition_by? order_by_expr_asc_desc CLOSE_PAR\n;\n\noffset:\n    COMMA signed_number\n;\n\ndefault_value:\n    COMMA signed_number\n;\n\npartition_by:\n    PARTITION_ BY_ expr+\n;\n\norder_by_expr:\n    ORDER_ BY_ expr+\n;\n\norder_by_expr_asc_desc:\n    ORDER_ BY_ expr_asc_desc\n;\n\nexpr_asc_desc:\n    expr asc_desc? (COMMA expr asc_desc?)*\n;\n\n//TODO BOTH OF THESE HAVE TO BE REWORKED TO FOLLOW THE SPEC\ninitial_select:\n    select_stmt\n;\n\nrecursive_select:\n    select_stmt\n;\n\nunary_operator:\n    MINUS\n    | PLUS\n    | TILDE\n    | NOT_\n;\n\nerror_message:\n    STRING_LITERAL\n;\n\nmodule_argument: // TODO check what exactly is permitted here\n    expr\n    | column_def\n;\n\ncolumn_alias:\n    IDENTIFIER\n    | STRING_LITERAL\n;\n\nkeyword:\n    ABORT_\n    | ACTION_\n    | ADD_\n    | AFTER_\n    | ALL_\n    | ALTER_\n    | ANALYZE_\n    | AND_\n    | AS_\n    | ASC_\n    | ATTACH_\n    | AUTOINCREMENT_\n    | BEFORE_\n    | BEGIN_\n    | BETWEEN_\n    | BY_\n    | CASCADE_\n    | CASE_\n    | CAST_\n    | CHECK_\n    | COLLATE_\n    | COLUMN_\n    | COMMIT_\n    | CONFLICT_\n    | CONSTRAINT_\n    | CREATE_\n    | CROSS_\n    | CURRENT_DATE_\n    | CURRENT_TIME_\n    | CURRENT_TIMESTAMP_\n    | DATABASE_\n    | DEFAULT_\n    | DEFERRABLE_\n    | DEFERRED_\n    | DELETE_\n    | DESC_\n    | DETACH_\n    | DISTINCT_\n    | DROP_\n    | EACH_\n    | ELSE_\n    | END_\n    | ESCAPE_\n    | EXCEPT_\n    | EXCLUSIVE_\n    | EXISTS_\n    | EXPLAIN_\n    | FAIL_\n    | FOR_\n    | FOREIGN_\n    | FROM_\n    | FULL_\n    | GLOB_\n    | GROUP_\n    | HAVING_\n    | IF_\n    | IGNORE_\n    | IMMEDIATE_\n    | IN_\n    | INDEX_\n    | INDEXED_\n    | INITIALLY_\n    | INNER_\n    | INSERT_\n    | INSTEAD_\n    | INTERSECT_\n    | INTO_\n    | IS_\n    | ISNULL_\n    | JOIN_\n    | KEY_\n    | LEFT_\n    | LIKE_\n    | LIMIT_\n    | MATCH_\n    | NATURAL_\n    | NO_\n    | NOT_\n    | NOTNULL_\n    | NULL_\n    | OF_\n    | OFFSET_\n    | ON_\n    | OR_\n    | ORDER_\n    | OUTER_\n    | PLAN_\n    | PRAGMA_\n    | PRIMARY_\n    | QUERY_\n    | RAISE_\n    | RECURSIVE_\n    | REFERENCES_\n    | REGEXP_\n    | REINDEX_\n    | RELEASE_\n    | RENAME_\n    | REPLACE_\n    | RESTRICT_\n    | RIGHT_\n    | ROLLBACK_\n    | ROW_\n    | ROWS_\n    | SAVEPOINT_\n    | SELECT_\n    | SET_\n    | TABLE_\n    | TEMP_\n    | TEMPORARY_\n    | THEN_\n    | TO_\n    | TRANSACTION_\n    | TRIGGER_\n    | UNION_\n    | UNIQUE_\n    | UPDATE_\n    | USING_\n    | VACUUM_\n    | VALUES_\n    | VIEW_\n    | VIRTUAL_\n    | WHEN_\n    | WHERE_\n    | WITH_\n    | WITHOUT_\n    | FIRST_VALUE_\n    | OVER_\n    | PARTITION_\n    | RANGE_\n    | PRECEDING_\n    | UNBOUNDED_\n    | CURRENT_\n    | FOLLOWING_\n    | CUME_DIST_\n    | DENSE_RANK_\n    | LAG_\n    | LAST_VALUE_\n    | LEAD_\n    | NTH_VALUE_\n    | NTILE_\n    | PERCENT_RANK_\n    | RANK_\n    | ROW_NUMBER_\n    | GENERATED_\n    | ALWAYS_\n    | STORED_\n    | TRUE_\n    | FALSE_\n    | WINDOW_\n    | NULLS_\n    | FIRST_\n    | LAST_\n    | FILTER_\n    | GROUPS_\n    | EXCLUDE_\n;\n\n// TODO: check all names below\n\nname:\n    any_name\n;\n\nfunction_name:\n    any_name\n;\n\nschema_name:\n    any_name\n;\n\ntable_name:\n    any_name\n;\n\ntable_or_index_name:\n    any_name\n;\n\ncolumn_name:\n    any_name\n;\n\ncollation_name:\n    any_name\n;\n\nforeign_table:\n    any_name\n;\n\nindex_name:\n    any_name\n;\n\ntrigger_name:\n    any_name\n;\n\nview_name:\n    any_name\n;\n\nmodule_name:\n    any_name\n;\n\npragma_name:\n    any_name\n;\n\nsavepoint_name:\n    any_name\n;\n\ntable_alias:\n    any_name\n;\n\ntransaction_name:\n    any_name\n;\n\nwindow_name:\n    any_name\n;\n\nalias:\n    any_name\n;\n\nfilename:\n    any_name\n;\n\nbase_window_name:\n    any_name\n;\n\nsimple_func:\n    any_name\n;\n\naggregate_func:\n    any_name\n;\n\ntable_function_name:\n    any_name\n;\n\nany_name:\n    IDENTIFIER\n    | keyword\n    | STRING_LITERAL\n    | OPEN_PAR any_name CLOSE_PAR\n;\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqliteparse/README.md",
    "content": "### SQLite parser based on ANTLR4\n\n#### Resources\n\n1. SQLite syntax: https://www.sqlite.org/syntaxdiagrams.html\n2. Grammar file: https://github.com/antlr/grammars-v4/tree/master/sql/sqlite\n\n#### Run codegen\n\n1. Install `antlr4`: https://github.com/antlr/antlr4/blob/master/doc/getting-started.md#unix\n2. Run:\n```bash\nantlr4 -Dlanguage=Go -package sqliteparse -visitor Lexer.g4 Parser.g4 \\\n  && mv _lexer.go lexer.go \\\n  && mv _parser.go parser.go \\\n  && rm *.interp *.tokens\n```"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqliteparse/lexer.go",
    "content": "// Code generated from Lexer.g4 by ANTLR 4.13.1. DO NOT EDIT.\n\npackage sqliteparse\n\nimport (\n\t\"fmt\"\n\t\"github.com/antlr4-go/antlr/v4\"\n\t\"sync\"\n\t\"unicode\"\n)\n\n// Suppress unused import error\nvar _ = fmt.Printf\nvar _ = sync.Once{}\nvar _ = unicode.IsLetter\n\ntype Lexer struct {\n\t*antlr.BaseLexer\n\tchannelNames []string\n\tmodeNames    []string\n\t// TODO: EOF string\n}\n\nvar LexerLexerStaticData struct {\n\tonce                   sync.Once\n\tserializedATN          []int32\n\tChannelNames           []string\n\tModeNames              []string\n\tLiteralNames           []string\n\tSymbolicNames          []string\n\tRuleNames              []string\n\tPredictionContextCache *antlr.PredictionContextCache\n\tatn                    *antlr.ATN\n\tdecisionToDFA          []*antlr.DFA\n}\n\nfunc lexerLexerInit() {\n\tstaticData := &LexerLexerStaticData\n\tstaticData.ChannelNames = []string{\n\t\t\"DEFAULT_TOKEN_CHANNEL\", \"HIDDEN\",\n\t}\n\tstaticData.ModeNames = []string{\n\t\t\"DEFAULT_MODE\",\n\t}\n\tstaticData.LiteralNames = []string{\n\t\t\"\", \"';'\", \"'.'\", \"'('\", \"')'\", \"','\", \"'='\", \"'*'\", \"'+'\", \"'-'\", \"'~'\",\n\t\t\"'||'\", \"'/'\", \"'%'\", \"'<<'\", \"'>>'\", \"'&'\", \"'|'\", \"'<'\", \"'<='\", \"'>'\",\n\t\t\"'>='\", \"'=='\", \"'!='\", \"'<>'\", \"'ABORT'\", \"'ACTION'\", \"'ADD'\", \"'AFTER'\",\n\t\t\"'ALL'\", \"'ALTER'\", \"'ANALYZE'\", \"'AND'\", \"'AS'\", \"'ASC'\", \"'ATTACH'\",\n\t\t\"'AUTOINCREMENT'\", \"'BEFORE'\", \"'BEGIN'\", \"'BETWEEN'\", \"'BY'\", \"'CASCADE'\",\n\t\t\"'CASE'\", \"'CAST'\", \"'CHECK'\", \"'COLLATE'\", \"'COLUMN'\", \"'COMMIT'\",\n\t\t\"'CONFLICT'\", \"'CONSTRAINT'\", \"'CREATE'\", \"'CROSS'\", \"'CURRENT_DATE'\",\n\t\t\"'CURRENT_TIME'\", \"'CURRENT_TIMESTAMP'\", \"'DATABASE'\", \"'DEFAULT'\",\n\t\t\"'DEFERRABLE'\", \"'DEFERRED'\", \"'DELETE'\", \"'DESC'\", \"'DETACH'\", \"'DISTINCT'\",\n\t\t\"'DROP'\", \"'EACH'\", \"'ELSE'\", \"'END'\", \"'ESCAPE'\", \"'EXCEPT'\", \"'EXCLUSIVE'\",\n\t\t\"'EXISTS'\", \"'EXPLAIN'\", \"'FAIL'\", \"'FOR'\", \"'FOREIGN'\", \"'FROM'\", \"'FULL'\",\n\t\t\"'GLOB'\", \"'GROUP'\", \"'HAVING'\", \"'IF'\", \"'IGNORE'\", \"'IMMEDIATE'\",\n\t\t\"'IN'\", \"'INDEX'\", \"'INDEXED'\", \"'INITIALLY'\", \"'INNER'\", \"'INSERT'\",\n\t\t\"'INSTEAD'\", \"'INTERSECT'\", \"'INTO'\", \"'IS'\", \"'ISNULL'\", \"'JOIN'\",\n\t\t\"'KEY'\", \"'LEFT'\", \"'LIKE'\", \"'LIMIT'\", \"'MATCH'\", \"'NATURAL'\", \"'NO'\",\n\t\t\"'NOT'\", \"'NOTNULL'\", \"'NULL'\", \"'OF'\", \"'OFFSET'\", \"'ON'\", \"'OR'\",\n\t\t\"'ORDER'\", \"'OUTER'\", \"'PLAN'\", \"'PRAGMA'\", \"'PRIMARY'\", \"'QUERY'\",\n\t\t\"'RAISE'\", \"'RECURSIVE'\", \"'REFERENCES'\", \"'REGEXP'\", \"'REINDEX'\", \"'RELEASE'\",\n\t\t\"'RENAME'\", \"'REPLACE'\", \"'RESTRICT'\", \"'RETURNING'\", \"'RIGHT'\", \"'ROLLBACK'\",\n\t\t\"'ROW'\", \"'ROWS'\", \"'SAVEPOINT'\", \"'SELECT'\", \"'SET'\", \"'TABLE'\", \"'TEMP'\",\n\t\t\"'TEMPORARY'\", \"'THEN'\", \"'TO'\", \"'TRANSACTION'\", \"'TRIGGER'\", \"'UNION'\",\n\t\t\"'UNIQUE'\", \"'UPDATE'\", \"'USING'\", \"'VACUUM'\", \"'VALUES'\", \"'VIEW'\",\n\t\t\"'VIRTUAL'\", \"'WHEN'\", \"'WHERE'\", \"'WITH'\", \"'WITHOUT'\", \"'FIRST_VALUE'\",\n\t\t\"'OVER'\", \"'PARTITION'\", \"'RANGE'\", \"'PRECEDING'\", \"'UNBOUNDED'\", \"'CURRENT'\",\n\t\t\"'FOLLOWING'\", \"'CUME_DIST'\", \"'DENSE_RANK'\", \"'LAG'\", \"'LAST_VALUE'\",\n\t\t\"'LEAD'\", \"'NTH_VALUE'\", \"'NTILE'\", \"'PERCENT_RANK'\", \"'RANK'\", \"'ROW_NUMBER'\",\n\t\t\"'GENERATED'\", \"'ALWAYS'\", \"'STORED'\", \"'TRUE'\", \"'FALSE'\", \"'WINDOW'\",\n\t\t\"'NULLS'\", \"'FIRST'\", \"'LAST'\", \"'FILTER'\", \"'GROUPS'\", \"'EXCLUDE'\",\n\t\t\"'TIES'\", \"'OTHERS'\", \"'DO'\", \"'NOTHING'\",\n\t}\n\tstaticData.SymbolicNames = []string{\n\t\t\"\", \"SCOL\", \"DOT\", \"OPEN_PAR\", \"CLOSE_PAR\", \"COMMA\", \"ASSIGN\", \"STAR\",\n\t\t\"PLUS\", \"MINUS\", \"TILDE\", \"PIPE2\", \"DIV\", \"MOD\", \"LT2\", \"GT2\", \"AMP\",\n\t\t\"PIPE\", \"LT\", \"LT_EQ\", \"GT\", \"GT_EQ\", \"EQ\", \"NOT_EQ1\", \"NOT_EQ2\", \"ABORT_\",\n\t\t\"ACTION_\", \"ADD_\", \"AFTER_\", \"ALL_\", \"ALTER_\", \"ANALYZE_\", \"AND_\", \"AS_\",\n\t\t\"ASC_\", \"ATTACH_\", \"AUTOINCREMENT_\", \"BEFORE_\", \"BEGIN_\", \"BETWEEN_\",\n\t\t\"BY_\", \"CASCADE_\", \"CASE_\", \"CAST_\", \"CHECK_\", \"COLLATE_\", \"COLUMN_\",\n\t\t\"COMMIT_\", \"CONFLICT_\", \"CONSTRAINT_\", \"CREATE_\", \"CROSS_\", \"CURRENT_DATE_\",\n\t\t\"CURRENT_TIME_\", \"CURRENT_TIMESTAMP_\", \"DATABASE_\", \"DEFAULT_\", \"DEFERRABLE_\",\n\t\t\"DEFERRED_\", \"DELETE_\", \"DESC_\", \"DETACH_\", \"DISTINCT_\", \"DROP_\", \"EACH_\",\n\t\t\"ELSE_\", \"END_\", \"ESCAPE_\", \"EXCEPT_\", \"EXCLUSIVE_\", \"EXISTS_\", \"EXPLAIN_\",\n\t\t\"FAIL_\", \"FOR_\", \"FOREIGN_\", \"FROM_\", \"FULL_\", \"GLOB_\", \"GROUP_\", \"HAVING_\",\n\t\t\"IF_\", \"IGNORE_\", \"IMMEDIATE_\", \"IN_\", \"INDEX_\", \"INDEXED_\", \"INITIALLY_\",\n\t\t\"INNER_\", \"INSERT_\", \"INSTEAD_\", \"INTERSECT_\", \"INTO_\", \"IS_\", \"ISNULL_\",\n\t\t\"JOIN_\", \"KEY_\", \"LEFT_\", \"LIKE_\", \"LIMIT_\", \"MATCH_\", \"NATURAL_\", \"NO_\",\n\t\t\"NOT_\", \"NOTNULL_\", \"NULL_\", \"OF_\", \"OFFSET_\", \"ON_\", \"OR_\", \"ORDER_\",\n\t\t\"OUTER_\", \"PLAN_\", \"PRAGMA_\", \"PRIMARY_\", \"QUERY_\", \"RAISE_\", \"RECURSIVE_\",\n\t\t\"REFERENCES_\", \"REGEXP_\", \"REINDEX_\", \"RELEASE_\", \"RENAME_\", \"REPLACE_\",\n\t\t\"RESTRICT_\", \"RETURNING_\", \"RIGHT_\", \"ROLLBACK_\", \"ROW_\", \"ROWS_\", \"SAVEPOINT_\",\n\t\t\"SELECT_\", \"SET_\", \"TABLE_\", \"TEMP_\", \"TEMPORARY_\", \"THEN_\", \"TO_\",\n\t\t\"TRANSACTION_\", \"TRIGGER_\", \"UNION_\", \"UNIQUE_\", \"UPDATE_\", \"USING_\",\n\t\t\"VACUUM_\", \"VALUES_\", \"VIEW_\", \"VIRTUAL_\", \"WHEN_\", \"WHERE_\", \"WITH_\",\n\t\t\"WITHOUT_\", \"FIRST_VALUE_\", \"OVER_\", \"PARTITION_\", \"RANGE_\", \"PRECEDING_\",\n\t\t\"UNBOUNDED_\", \"CURRENT_\", \"FOLLOWING_\", \"CUME_DIST_\", \"DENSE_RANK_\",\n\t\t\"LAG_\", \"LAST_VALUE_\", \"LEAD_\", \"NTH_VALUE_\", \"NTILE_\", \"PERCENT_RANK_\",\n\t\t\"RANK_\", \"ROW_NUMBER_\", \"GENERATED_\", \"ALWAYS_\", \"STORED_\", \"TRUE_\",\n\t\t\"FALSE_\", \"WINDOW_\", \"NULLS_\", \"FIRST_\", \"LAST_\", \"FILTER_\", \"GROUPS_\",\n\t\t\"EXCLUDE_\", \"TIES_\", \"OTHERS_\", \"DO_\", \"NOTHING_\", \"IDENTIFIER\", \"NUMERIC_LITERAL\",\n\t\t\"BIND_PARAMETER\", \"STRING_LITERAL\", \"BLOB_LITERAL\", \"SINGLE_LINE_COMMENT\",\n\t\t\"MULTILINE_COMMENT\", \"SPACES\", \"UNEXPECTED_CHAR\",\n\t}\n\tstaticData.RuleNames = []string{\n\t\t\"SCOL\", \"DOT\", \"OPEN_PAR\", \"CLOSE_PAR\", \"COMMA\", \"ASSIGN\", \"STAR\", \"PLUS\",\n\t\t\"MINUS\", \"TILDE\", \"PIPE2\", \"DIV\", \"MOD\", \"LT2\", \"GT2\", \"AMP\", \"PIPE\",\n\t\t\"LT\", \"LT_EQ\", \"GT\", \"GT_EQ\", \"EQ\", \"NOT_EQ1\", \"NOT_EQ2\", \"ABORT_\",\n\t\t\"ACTION_\", \"ADD_\", \"AFTER_\", \"ALL_\", \"ALTER_\", \"ANALYZE_\", \"AND_\", \"AS_\",\n\t\t\"ASC_\", \"ATTACH_\", \"AUTOINCREMENT_\", \"BEFORE_\", \"BEGIN_\", \"BETWEEN_\",\n\t\t\"BY_\", \"CASCADE_\", \"CASE_\", \"CAST_\", \"CHECK_\", \"COLLATE_\", \"COLUMN_\",\n\t\t\"COMMIT_\", \"CONFLICT_\", \"CONSTRAINT_\", \"CREATE_\", \"CROSS_\", \"CURRENT_DATE_\",\n\t\t\"CURRENT_TIME_\", \"CURRENT_TIMESTAMP_\", \"DATABASE_\", \"DEFAULT_\", \"DEFERRABLE_\",\n\t\t\"DEFERRED_\", \"DELETE_\", \"DESC_\", \"DETACH_\", \"DISTINCT_\", \"DROP_\", \"EACH_\",\n\t\t\"ELSE_\", \"END_\", \"ESCAPE_\", \"EXCEPT_\", \"EXCLUSIVE_\", \"EXISTS_\", \"EXPLAIN_\",\n\t\t\"FAIL_\", \"FOR_\", \"FOREIGN_\", \"FROM_\", \"FULL_\", \"GLOB_\", \"GROUP_\", \"HAVING_\",\n\t\t\"IF_\", \"IGNORE_\", \"IMMEDIATE_\", \"IN_\", \"INDEX_\", \"INDEXED_\", \"INITIALLY_\",\n\t\t\"INNER_\", \"INSERT_\", \"INSTEAD_\", \"INTERSECT_\", \"INTO_\", \"IS_\", \"ISNULL_\",\n\t\t\"JOIN_\", \"KEY_\", \"LEFT_\", \"LIKE_\", \"LIMIT_\", \"MATCH_\", \"NATURAL_\", \"NO_\",\n\t\t\"NOT_\", \"NOTNULL_\", \"NULL_\", \"OF_\", \"OFFSET_\", \"ON_\", \"OR_\", \"ORDER_\",\n\t\t\"OUTER_\", \"PLAN_\", \"PRAGMA_\", \"PRIMARY_\", \"QUERY_\", \"RAISE_\", \"RECURSIVE_\",\n\t\t\"REFERENCES_\", \"REGEXP_\", \"REINDEX_\", \"RELEASE_\", \"RENAME_\", \"REPLACE_\",\n\t\t\"RESTRICT_\", \"RETURNING_\", \"RIGHT_\", \"ROLLBACK_\", \"ROW_\", \"ROWS_\", \"SAVEPOINT_\",\n\t\t\"SELECT_\", \"SET_\", \"TABLE_\", \"TEMP_\", \"TEMPORARY_\", \"THEN_\", \"TO_\",\n\t\t\"TRANSACTION_\", \"TRIGGER_\", \"UNION_\", \"UNIQUE_\", \"UPDATE_\", \"USING_\",\n\t\t\"VACUUM_\", \"VALUES_\", \"VIEW_\", \"VIRTUAL_\", \"WHEN_\", \"WHERE_\", \"WITH_\",\n\t\t\"WITHOUT_\", \"FIRST_VALUE_\", \"OVER_\", \"PARTITION_\", \"RANGE_\", \"PRECEDING_\",\n\t\t\"UNBOUNDED_\", \"CURRENT_\", \"FOLLOWING_\", \"CUME_DIST_\", \"DENSE_RANK_\",\n\t\t\"LAG_\", \"LAST_VALUE_\", \"LEAD_\", \"NTH_VALUE_\", \"NTILE_\", \"PERCENT_RANK_\",\n\t\t\"RANK_\", \"ROW_NUMBER_\", \"GENERATED_\", \"ALWAYS_\", \"STORED_\", \"TRUE_\",\n\t\t\"FALSE_\", \"WINDOW_\", \"NULLS_\", \"FIRST_\", \"LAST_\", \"FILTER_\", \"GROUPS_\",\n\t\t\"EXCLUDE_\", \"TIES_\", \"OTHERS_\", \"DO_\", \"NOTHING_\", \"IDENTIFIER\", \"NUMERIC_LITERAL\",\n\t\t\"BIND_PARAMETER\", \"STRING_LITERAL\", \"BLOB_LITERAL\", \"SINGLE_LINE_COMMENT\",\n\t\t\"MULTILINE_COMMENT\", \"SPACES\", \"UNEXPECTED_CHAR\", \"HEX_DIGIT\", \"DIGIT\",\n\t}\n\tstaticData.PredictionContextCache = antlr.NewPredictionContextCache()\n\tstaticData.serializedATN = []int32{\n\t\t4, 0, 193, 1704, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3,\n\t\t2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9,\n\t\t2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2,\n\t\t15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20,\n\t\t7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7,\n\t\t25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30,\n\t\t2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2,\n\t\t36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41,\n\t\t7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7,\n\t\t46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51,\n\t\t2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2,\n\t\t57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62,\n\t\t7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7,\n\t\t67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72,\n\t\t2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2,\n\t\t78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83,\n\t\t7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7,\n\t\t88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93,\n\t\t2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2,\n\t\t99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103,\n\t\t2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108,\n\t\t7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112,\n\t\t2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117,\n\t\t7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121,\n\t\t2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126,\n\t\t7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130,\n\t\t2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135,\n\t\t7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139,\n\t\t2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144,\n\t\t7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148,\n\t\t2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153,\n\t\t7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157,\n\t\t2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162,\n\t\t7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166,\n\t\t2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171,\n\t\t7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175,\n\t\t2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180,\n\t\t7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184,\n\t\t2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189,\n\t\t7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193,\n\t\t2, 194, 7, 194, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1,\n\t\t4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1,\n\t\t10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14,\n\t\t1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1,\n\t\t19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22,\n\t\t1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1,\n\t\t25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27,\n\t\t1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1,\n\t\t29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30,\n\t\t1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 33, 1,\n\t\t33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35,\n\t\t1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1,\n\t\t35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37,\n\t\t1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1,\n\t\t38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40,\n\t\t1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1,\n\t\t42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44,\n\t\t1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1,\n\t\t45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47,\n\t\t1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1,\n\t\t48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49,\n\t\t1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1,\n\t\t50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51,\n\t\t1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1,\n\t\t52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53,\n\t\t1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1,\n\t\t53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54,\n\t\t1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1,\n\t\t56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57,\n\t\t1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1,\n\t\t58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60,\n\t\t1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1,\n\t\t61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63,\n\t\t1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1,\n\t\t65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67,\n\t\t1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1,\n\t\t68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69,\n\t\t1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1,\n\t\t71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73,\n\t\t1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1,\n\t\t74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76,\n\t\t1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1,\n\t\t78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80,\n\t\t1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1,\n\t\t81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83,\n\t\t1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1,\n\t\t85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86,\n\t\t1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1,\n\t\t88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89,\n\t\t1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1,\n\t\t90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92,\n\t\t1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1,\n\t\t95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97,\n\t\t1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1,\n\t\t98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1,\n\t\t100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1,\n\t\t102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1,\n\t\t103, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1,\n\t\t105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 108, 1,\n\t\t108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 109, 1,\n\t\t109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1,\n\t\t111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1,\n\t\t112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1,\n\t\t113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1,\n\t\t115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1,\n\t\t116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1,\n\t\t116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1,\n\t\t118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1,\n\t\t119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1,\n\t\t120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1,\n\t\t121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1,\n\t\t122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1,\n\t\t123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1,\n\t\t124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1,\n\t\t125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1,\n\t\t127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 1,\n\t\t128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1, 129, 1,\n\t\t130, 1, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1,\n\t\t131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1,\n\t\t133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1,\n\t\t134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1,\n\t\t136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1,\n\t\t137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 138, 1,\n\t\t138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1,\n\t\t139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1,\n\t\t140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1,\n\t\t142, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 1, 143, 1, 143, 1, 143, 1,\n\t\t143, 1, 143, 1, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 144, 1, 145, 1,\n\t\t145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1,\n\t\t146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1, 147, 1,\n\t\t148, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1,\n\t\t149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1,\n\t\t150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1,\n\t\t151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1,\n\t\t152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 153, 1,\n\t\t153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1,\n\t\t154, 1, 154, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1,\n\t\t155, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1,\n\t\t156, 1, 156, 1, 157, 1, 157, 1, 157, 1, 157, 1, 157, 1, 157, 1, 157, 1,\n\t\t157, 1, 157, 1, 157, 1, 158, 1, 158, 1, 158, 1, 158, 1, 158, 1, 158, 1,\n\t\t158, 1, 158, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1,\n\t\t159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1,\n\t\t160, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1,\n\t\t161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 1,\n\t\t163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1,\n\t\t164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1,\n\t\t165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1,\n\t\t165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1,\n\t\t167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1,\n\t\t168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1,\n\t\t169, 1, 169, 1, 169, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1,\n\t\t170, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1,\n\t\t171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 1, 173, 1,\n\t\t173, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1,\n\t\t174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1,\n\t\t176, 1, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1,\n\t\t177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 1, 178, 1, 178, 1, 178, 1,\n\t\t179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 180, 1,\n\t\t180, 1, 180, 1, 180, 1, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 1,\n\t\t181, 1, 181, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 1,\n\t\t183, 1, 183, 1, 183, 1, 183, 1, 184, 1, 184, 1, 184, 1, 184, 5, 184, 1562,\n\t\t8, 184, 10, 184, 12, 184, 1565, 9, 184, 1, 184, 1, 184, 1, 184, 1, 184,\n\t\t1, 184, 5, 184, 1572, 8, 184, 10, 184, 12, 184, 1575, 9, 184, 1, 184, 1,\n\t\t184, 1, 184, 5, 184, 1580, 8, 184, 10, 184, 12, 184, 1583, 9, 184, 1, 184,\n\t\t1, 184, 1, 184, 5, 184, 1588, 8, 184, 10, 184, 12, 184, 1591, 9, 184, 3,\n\t\t184, 1593, 8, 184, 1, 185, 4, 185, 1596, 8, 185, 11, 185, 12, 185, 1597,\n\t\t1, 185, 1, 185, 5, 185, 1602, 8, 185, 10, 185, 12, 185, 1605, 9, 185, 3,\n\t\t185, 1607, 8, 185, 1, 185, 1, 185, 4, 185, 1611, 8, 185, 11, 185, 12, 185,\n\t\t1612, 3, 185, 1615, 8, 185, 1, 185, 1, 185, 3, 185, 1619, 8, 185, 1, 185,\n\t\t4, 185, 1622, 8, 185, 11, 185, 12, 185, 1623, 3, 185, 1626, 8, 185, 1,\n\t\t185, 1, 185, 1, 185, 1, 185, 4, 185, 1632, 8, 185, 11, 185, 12, 185, 1633,\n\t\t3, 185, 1636, 8, 185, 1, 186, 1, 186, 5, 186, 1640, 8, 186, 10, 186, 12,\n\t\t186, 1643, 9, 186, 1, 186, 1, 186, 3, 186, 1647, 8, 186, 1, 187, 1, 187,\n\t\t1, 187, 1, 187, 5, 187, 1653, 8, 187, 10, 187, 12, 187, 1656, 9, 187, 1,\n\t\t187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 5,\n\t\t189, 1667, 8, 189, 10, 189, 12, 189, 1670, 9, 189, 1, 189, 3, 189, 1673,\n\t\t8, 189, 1, 189, 1, 189, 3, 189, 1677, 8, 189, 1, 189, 1, 189, 1, 190, 1,\n\t\t190, 1, 190, 1, 190, 5, 190, 1685, 8, 190, 10, 190, 12, 190, 1688, 9, 190,\n\t\t1, 190, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191,\n\t\t1, 192, 1, 192, 1, 193, 1, 193, 1, 194, 1, 194, 1, 1686, 0, 195, 1, 1,\n\t\t3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23,\n\t\t12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41,\n\t\t21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59,\n\t\t30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77,\n\t\t39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 95,\n\t\t48, 97, 49, 99, 50, 101, 51, 103, 52, 105, 53, 107, 54, 109, 55, 111, 56,\n\t\t113, 57, 115, 58, 117, 59, 119, 60, 121, 61, 123, 62, 125, 63, 127, 64,\n\t\t129, 65, 131, 66, 133, 67, 135, 68, 137, 69, 139, 70, 141, 71, 143, 72,\n\t\t145, 73, 147, 74, 149, 75, 151, 76, 153, 77, 155, 78, 157, 79, 159, 80,\n\t\t161, 81, 163, 82, 165, 83, 167, 84, 169, 85, 171, 86, 173, 87, 175, 88,\n\t\t177, 89, 179, 90, 181, 91, 183, 92, 185, 93, 187, 94, 189, 95, 191, 96,\n\t\t193, 97, 195, 98, 197, 99, 199, 100, 201, 101, 203, 102, 205, 103, 207,\n\t\t104, 209, 105, 211, 106, 213, 107, 215, 108, 217, 109, 219, 110, 221, 111,\n\t\t223, 112, 225, 113, 227, 114, 229, 115, 231, 116, 233, 117, 235, 118, 237,\n\t\t119, 239, 120, 241, 121, 243, 122, 245, 123, 247, 124, 249, 125, 251, 126,\n\t\t253, 127, 255, 128, 257, 129, 259, 130, 261, 131, 263, 132, 265, 133, 267,\n\t\t134, 269, 135, 271, 136, 273, 137, 275, 138, 277, 139, 279, 140, 281, 141,\n\t\t283, 142, 285, 143, 287, 144, 289, 145, 291, 146, 293, 147, 295, 148, 297,\n\t\t149, 299, 150, 301, 151, 303, 152, 305, 153, 307, 154, 309, 155, 311, 156,\n\t\t313, 157, 315, 158, 317, 159, 319, 160, 321, 161, 323, 162, 325, 163, 327,\n\t\t164, 329, 165, 331, 166, 333, 167, 335, 168, 337, 169, 339, 170, 341, 171,\n\t\t343, 172, 345, 173, 347, 174, 349, 175, 351, 176, 353, 177, 355, 178, 357,\n\t\t179, 359, 180, 361, 181, 363, 182, 365, 183, 367, 184, 369, 185, 371, 186,\n\t\t373, 187, 375, 188, 377, 189, 379, 190, 381, 191, 383, 192, 385, 193, 387,\n\t\t0, 389, 0, 1, 0, 38, 2, 0, 65, 65, 97, 97, 2, 0, 66, 66, 98, 98, 2, 0,\n\t\t79, 79, 111, 111, 2, 0, 82, 82, 114, 114, 2, 0, 84, 84, 116, 116, 2, 0,\n\t\t67, 67, 99, 99, 2, 0, 73, 73, 105, 105, 2, 0, 78, 78, 110, 110, 2, 0, 68,\n\t\t68, 100, 100, 2, 0, 70, 70, 102, 102, 2, 0, 69, 69, 101, 101, 2, 0, 76,\n\t\t76, 108, 108, 2, 0, 89, 89, 121, 121, 2, 0, 90, 90, 122, 122, 2, 0, 83,\n\t\t83, 115, 115, 2, 0, 72, 72, 104, 104, 2, 0, 85, 85, 117, 117, 2, 0, 77,\n\t\t77, 109, 109, 2, 0, 71, 71, 103, 103, 2, 0, 87, 87, 119, 119, 2, 0, 75,\n\t\t75, 107, 107, 2, 0, 80, 80, 112, 112, 2, 0, 88, 88, 120, 120, 2, 0, 86,\n\t\t86, 118, 118, 2, 0, 74, 74, 106, 106, 2, 0, 81, 81, 113, 113, 1, 0, 34,\n\t\t34, 1, 0, 96, 96, 1, 0, 93, 93, 3, 0, 65, 90, 95, 95, 97, 122, 4, 0, 48,\n\t\t57, 65, 90, 95, 95, 97, 122, 2, 0, 43, 43, 45, 45, 3, 0, 36, 36, 58, 58,\n\t\t64, 64, 1, 0, 39, 39, 2, 0, 10, 10, 13, 13, 3, 0, 9, 11, 13, 13, 32, 32,\n\t\t3, 0, 48, 57, 65, 70, 97, 102, 1, 0, 48, 57, 1728, 0, 1, 1, 0, 0, 0, 0,\n\t\t3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0,\n\t\t11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0,\n\t\t0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0,\n\t\t0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0,\n\t\t0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1,\n\t\t0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49,\n\t\t1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0,\n\t\t57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0,\n\t\t0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0,\n\t\t0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0,\n\t\t0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1,\n\t\t0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95,\n\t\t1, 0, 0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0,\n\t\t103, 1, 0, 0, 0, 0, 105, 1, 0, 0, 0, 0, 107, 1, 0, 0, 0, 0, 109, 1, 0,\n\t\t0, 0, 0, 111, 1, 0, 0, 0, 0, 113, 1, 0, 0, 0, 0, 115, 1, 0, 0, 0, 0, 117,\n\t\t1, 0, 0, 0, 0, 119, 1, 0, 0, 0, 0, 121, 1, 0, 0, 0, 0, 123, 1, 0, 0, 0,\n\t\t0, 125, 1, 0, 0, 0, 0, 127, 1, 0, 0, 0, 0, 129, 1, 0, 0, 0, 0, 131, 1,\n\t\t0, 0, 0, 0, 133, 1, 0, 0, 0, 0, 135, 1, 0, 0, 0, 0, 137, 1, 0, 0, 0, 0,\n\t\t139, 1, 0, 0, 0, 0, 141, 1, 0, 0, 0, 0, 143, 1, 0, 0, 0, 0, 145, 1, 0,\n\t\t0, 0, 0, 147, 1, 0, 0, 0, 0, 149, 1, 0, 0, 0, 0, 151, 1, 0, 0, 0, 0, 153,\n\t\t1, 0, 0, 0, 0, 155, 1, 0, 0, 0, 0, 157, 1, 0, 0, 0, 0, 159, 1, 0, 0, 0,\n\t\t0, 161, 1, 0, 0, 0, 0, 163, 1, 0, 0, 0, 0, 165, 1, 0, 0, 0, 0, 167, 1,\n\t\t0, 0, 0, 0, 169, 1, 0, 0, 0, 0, 171, 1, 0, 0, 0, 0, 173, 1, 0, 0, 0, 0,\n\t\t175, 1, 0, 0, 0, 0, 177, 1, 0, 0, 0, 0, 179, 1, 0, 0, 0, 0, 181, 1, 0,\n\t\t0, 0, 0, 183, 1, 0, 0, 0, 0, 185, 1, 0, 0, 0, 0, 187, 1, 0, 0, 0, 0, 189,\n\t\t1, 0, 0, 0, 0, 191, 1, 0, 0, 0, 0, 193, 1, 0, 0, 0, 0, 195, 1, 0, 0, 0,\n\t\t0, 197, 1, 0, 0, 0, 0, 199, 1, 0, 0, 0, 0, 201, 1, 0, 0, 0, 0, 203, 1,\n\t\t0, 0, 0, 0, 205, 1, 0, 0, 0, 0, 207, 1, 0, 0, 0, 0, 209, 1, 0, 0, 0, 0,\n\t\t211, 1, 0, 0, 0, 0, 213, 1, 0, 0, 0, 0, 215, 1, 0, 0, 0, 0, 217, 1, 0,\n\t\t0, 0, 0, 219, 1, 0, 0, 0, 0, 221, 1, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 225,\n\t\t1, 0, 0, 0, 0, 227, 1, 0, 0, 0, 0, 229, 1, 0, 0, 0, 0, 231, 1, 0, 0, 0,\n\t\t0, 233, 1, 0, 0, 0, 0, 235, 1, 0, 0, 0, 0, 237, 1, 0, 0, 0, 0, 239, 1,\n\t\t0, 0, 0, 0, 241, 1, 0, 0, 0, 0, 243, 1, 0, 0, 0, 0, 245, 1, 0, 0, 0, 0,\n\t\t247, 1, 0, 0, 0, 0, 249, 1, 0, 0, 0, 0, 251, 1, 0, 0, 0, 0, 253, 1, 0,\n\t\t0, 0, 0, 255, 1, 0, 0, 0, 0, 257, 1, 0, 0, 0, 0, 259, 1, 0, 0, 0, 0, 261,\n\t\t1, 0, 0, 0, 0, 263, 1, 0, 0, 0, 0, 265, 1, 0, 0, 0, 0, 267, 1, 0, 0, 0,\n\t\t0, 269, 1, 0, 0, 0, 0, 271, 1, 0, 0, 0, 0, 273, 1, 0, 0, 0, 0, 275, 1,\n\t\t0, 0, 0, 0, 277, 1, 0, 0, 0, 0, 279, 1, 0, 0, 0, 0, 281, 1, 0, 0, 0, 0,\n\t\t283, 1, 0, 0, 0, 0, 285, 1, 0, 0, 0, 0, 287, 1, 0, 0, 0, 0, 289, 1, 0,\n\t\t0, 0, 0, 291, 1, 0, 0, 0, 0, 293, 1, 0, 0, 0, 0, 295, 1, 0, 0, 0, 0, 297,\n\t\t1, 0, 0, 0, 0, 299, 1, 0, 0, 0, 0, 301, 1, 0, 0, 0, 0, 303, 1, 0, 0, 0,\n\t\t0, 305, 1, 0, 0, 0, 0, 307, 1, 0, 0, 0, 0, 309, 1, 0, 0, 0, 0, 311, 1,\n\t\t0, 0, 0, 0, 313, 1, 0, 0, 0, 0, 315, 1, 0, 0, 0, 0, 317, 1, 0, 0, 0, 0,\n\t\t319, 1, 0, 0, 0, 0, 321, 1, 0, 0, 0, 0, 323, 1, 0, 0, 0, 0, 325, 1, 0,\n\t\t0, 0, 0, 327, 1, 0, 0, 0, 0, 329, 1, 0, 0, 0, 0, 331, 1, 0, 0, 0, 0, 333,\n\t\t1, 0, 0, 0, 0, 335, 1, 0, 0, 0, 0, 337, 1, 0, 0, 0, 0, 339, 1, 0, 0, 0,\n\t\t0, 341, 1, 0, 0, 0, 0, 343, 1, 0, 0, 0, 0, 345, 1, 0, 0, 0, 0, 347, 1,\n\t\t0, 0, 0, 0, 349, 1, 0, 0, 0, 0, 351, 1, 0, 0, 0, 0, 353, 1, 0, 0, 0, 0,\n\t\t355, 1, 0, 0, 0, 0, 357, 1, 0, 0, 0, 0, 359, 1, 0, 0, 0, 0, 361, 1, 0,\n\t\t0, 0, 0, 363, 1, 0, 0, 0, 0, 365, 1, 0, 0, 0, 0, 367, 1, 0, 0, 0, 0, 369,\n\t\t1, 0, 0, 0, 0, 371, 1, 0, 0, 0, 0, 373, 1, 0, 0, 0, 0, 375, 1, 0, 0, 0,\n\t\t0, 377, 1, 0, 0, 0, 0, 379, 1, 0, 0, 0, 0, 381, 1, 0, 0, 0, 0, 383, 1,\n\t\t0, 0, 0, 0, 385, 1, 0, 0, 0, 1, 391, 1, 0, 0, 0, 3, 393, 1, 0, 0, 0, 5,\n\t\t395, 1, 0, 0, 0, 7, 397, 1, 0, 0, 0, 9, 399, 1, 0, 0, 0, 11, 401, 1, 0,\n\t\t0, 0, 13, 403, 1, 0, 0, 0, 15, 405, 1, 0, 0, 0, 17, 407, 1, 0, 0, 0, 19,\n\t\t409, 1, 0, 0, 0, 21, 411, 1, 0, 0, 0, 23, 414, 1, 0, 0, 0, 25, 416, 1,\n\t\t0, 0, 0, 27, 418, 1, 0, 0, 0, 29, 421, 1, 0, 0, 0, 31, 424, 1, 0, 0, 0,\n\t\t33, 426, 1, 0, 0, 0, 35, 428, 1, 0, 0, 0, 37, 430, 1, 0, 0, 0, 39, 433,\n\t\t1, 0, 0, 0, 41, 435, 1, 0, 0, 0, 43, 438, 1, 0, 0, 0, 45, 441, 1, 0, 0,\n\t\t0, 47, 444, 1, 0, 0, 0, 49, 447, 1, 0, 0, 0, 51, 453, 1, 0, 0, 0, 53, 460,\n\t\t1, 0, 0, 0, 55, 464, 1, 0, 0, 0, 57, 470, 1, 0, 0, 0, 59, 474, 1, 0, 0,\n\t\t0, 61, 480, 1, 0, 0, 0, 63, 488, 1, 0, 0, 0, 65, 492, 1, 0, 0, 0, 67, 495,\n\t\t1, 0, 0, 0, 69, 499, 1, 0, 0, 0, 71, 506, 1, 0, 0, 0, 73, 520, 1, 0, 0,\n\t\t0, 75, 527, 1, 0, 0, 0, 77, 533, 1, 0, 0, 0, 79, 541, 1, 0, 0, 0, 81, 544,\n\t\t1, 0, 0, 0, 83, 552, 1, 0, 0, 0, 85, 557, 1, 0, 0, 0, 87, 562, 1, 0, 0,\n\t\t0, 89, 568, 1, 0, 0, 0, 91, 576, 1, 0, 0, 0, 93, 583, 1, 0, 0, 0, 95, 590,\n\t\t1, 0, 0, 0, 97, 599, 1, 0, 0, 0, 99, 610, 1, 0, 0, 0, 101, 617, 1, 0, 0,\n\t\t0, 103, 623, 1, 0, 0, 0, 105, 636, 1, 0, 0, 0, 107, 649, 1, 0, 0, 0, 109,\n\t\t667, 1, 0, 0, 0, 111, 676, 1, 0, 0, 0, 113, 684, 1, 0, 0, 0, 115, 695,\n\t\t1, 0, 0, 0, 117, 704, 1, 0, 0, 0, 119, 711, 1, 0, 0, 0, 121, 716, 1, 0,\n\t\t0, 0, 123, 723, 1, 0, 0, 0, 125, 732, 1, 0, 0, 0, 127, 737, 1, 0, 0, 0,\n\t\t129, 742, 1, 0, 0, 0, 131, 747, 1, 0, 0, 0, 133, 751, 1, 0, 0, 0, 135,\n\t\t758, 1, 0, 0, 0, 137, 765, 1, 0, 0, 0, 139, 775, 1, 0, 0, 0, 141, 782,\n\t\t1, 0, 0, 0, 143, 790, 1, 0, 0, 0, 145, 795, 1, 0, 0, 0, 147, 799, 1, 0,\n\t\t0, 0, 149, 807, 1, 0, 0, 0, 151, 812, 1, 0, 0, 0, 153, 817, 1, 0, 0, 0,\n\t\t155, 822, 1, 0, 0, 0, 157, 828, 1, 0, 0, 0, 159, 835, 1, 0, 0, 0, 161,\n\t\t838, 1, 0, 0, 0, 163, 845, 1, 0, 0, 0, 165, 855, 1, 0, 0, 0, 167, 858,\n\t\t1, 0, 0, 0, 169, 864, 1, 0, 0, 0, 171, 872, 1, 0, 0, 0, 173, 882, 1, 0,\n\t\t0, 0, 175, 888, 1, 0, 0, 0, 177, 895, 1, 0, 0, 0, 179, 903, 1, 0, 0, 0,\n\t\t181, 913, 1, 0, 0, 0, 183, 918, 1, 0, 0, 0, 185, 921, 1, 0, 0, 0, 187,\n\t\t928, 1, 0, 0, 0, 189, 933, 1, 0, 0, 0, 191, 937, 1, 0, 0, 0, 193, 942,\n\t\t1, 0, 0, 0, 195, 947, 1, 0, 0, 0, 197, 953, 1, 0, 0, 0, 199, 959, 1, 0,\n\t\t0, 0, 201, 967, 1, 0, 0, 0, 203, 970, 1, 0, 0, 0, 205, 974, 1, 0, 0, 0,\n\t\t207, 982, 1, 0, 0, 0, 209, 987, 1, 0, 0, 0, 211, 990, 1, 0, 0, 0, 213,\n\t\t997, 1, 0, 0, 0, 215, 1000, 1, 0, 0, 0, 217, 1003, 1, 0, 0, 0, 219, 1009,\n\t\t1, 0, 0, 0, 221, 1015, 1, 0, 0, 0, 223, 1020, 1, 0, 0, 0, 225, 1027, 1,\n\t\t0, 0, 0, 227, 1035, 1, 0, 0, 0, 229, 1041, 1, 0, 0, 0, 231, 1047, 1, 0,\n\t\t0, 0, 233, 1057, 1, 0, 0, 0, 235, 1068, 1, 0, 0, 0, 237, 1075, 1, 0, 0,\n\t\t0, 239, 1083, 1, 0, 0, 0, 241, 1091, 1, 0, 0, 0, 243, 1098, 1, 0, 0, 0,\n\t\t245, 1106, 1, 0, 0, 0, 247, 1115, 1, 0, 0, 0, 249, 1125, 1, 0, 0, 0, 251,\n\t\t1131, 1, 0, 0, 0, 253, 1140, 1, 0, 0, 0, 255, 1144, 1, 0, 0, 0, 257, 1149,\n\t\t1, 0, 0, 0, 259, 1159, 1, 0, 0, 0, 261, 1166, 1, 0, 0, 0, 263, 1170, 1,\n\t\t0, 0, 0, 265, 1176, 1, 0, 0, 0, 267, 1181, 1, 0, 0, 0, 269, 1191, 1, 0,\n\t\t0, 0, 271, 1196, 1, 0, 0, 0, 273, 1199, 1, 0, 0, 0, 275, 1211, 1, 0, 0,\n\t\t0, 277, 1219, 1, 0, 0, 0, 279, 1225, 1, 0, 0, 0, 281, 1232, 1, 0, 0, 0,\n\t\t283, 1239, 1, 0, 0, 0, 285, 1245, 1, 0, 0, 0, 287, 1252, 1, 0, 0, 0, 289,\n\t\t1259, 1, 0, 0, 0, 291, 1264, 1, 0, 0, 0, 293, 1272, 1, 0, 0, 0, 295, 1277,\n\t\t1, 0, 0, 0, 297, 1283, 1, 0, 0, 0, 299, 1288, 1, 0, 0, 0, 301, 1296, 1,\n\t\t0, 0, 0, 303, 1308, 1, 0, 0, 0, 305, 1313, 1, 0, 0, 0, 307, 1323, 1, 0,\n\t\t0, 0, 309, 1329, 1, 0, 0, 0, 311, 1339, 1, 0, 0, 0, 313, 1349, 1, 0, 0,\n\t\t0, 315, 1357, 1, 0, 0, 0, 317, 1367, 1, 0, 0, 0, 319, 1377, 1, 0, 0, 0,\n\t\t321, 1388, 1, 0, 0, 0, 323, 1392, 1, 0, 0, 0, 325, 1403, 1, 0, 0, 0, 327,\n\t\t1408, 1, 0, 0, 0, 329, 1418, 1, 0, 0, 0, 331, 1424, 1, 0, 0, 0, 333, 1437,\n\t\t1, 0, 0, 0, 335, 1442, 1, 0, 0, 0, 337, 1453, 1, 0, 0, 0, 339, 1463, 1,\n\t\t0, 0, 0, 341, 1470, 1, 0, 0, 0, 343, 1477, 1, 0, 0, 0, 345, 1482, 1, 0,\n\t\t0, 0, 347, 1488, 1, 0, 0, 0, 349, 1495, 1, 0, 0, 0, 351, 1501, 1, 0, 0,\n\t\t0, 353, 1507, 1, 0, 0, 0, 355, 1512, 1, 0, 0, 0, 357, 1519, 1, 0, 0, 0,\n\t\t359, 1526, 1, 0, 0, 0, 361, 1534, 1, 0, 0, 0, 363, 1539, 1, 0, 0, 0, 365,\n\t\t1546, 1, 0, 0, 0, 367, 1549, 1, 0, 0, 0, 369, 1592, 1, 0, 0, 0, 371, 1635,\n\t\t1, 0, 0, 0, 373, 1646, 1, 0, 0, 0, 375, 1648, 1, 0, 0, 0, 377, 1659, 1,\n\t\t0, 0, 0, 379, 1662, 1, 0, 0, 0, 381, 1680, 1, 0, 0, 0, 383, 1694, 1, 0,\n\t\t0, 0, 385, 1698, 1, 0, 0, 0, 387, 1700, 1, 0, 0, 0, 389, 1702, 1, 0, 0,\n\t\t0, 391, 392, 5, 59, 0, 0, 392, 2, 1, 0, 0, 0, 393, 394, 5, 46, 0, 0, 394,\n\t\t4, 1, 0, 0, 0, 395, 396, 5, 40, 0, 0, 396, 6, 1, 0, 0, 0, 397, 398, 5,\n\t\t41, 0, 0, 398, 8, 1, 0, 0, 0, 399, 400, 5, 44, 0, 0, 400, 10, 1, 0, 0,\n\t\t0, 401, 402, 5, 61, 0, 0, 402, 12, 1, 0, 0, 0, 403, 404, 5, 42, 0, 0, 404,\n\t\t14, 1, 0, 0, 0, 405, 406, 5, 43, 0, 0, 406, 16, 1, 0, 0, 0, 407, 408, 5,\n\t\t45, 0, 0, 408, 18, 1, 0, 0, 0, 409, 410, 5, 126, 0, 0, 410, 20, 1, 0, 0,\n\t\t0, 411, 412, 5, 124, 0, 0, 412, 413, 5, 124, 0, 0, 413, 22, 1, 0, 0, 0,\n\t\t414, 415, 5, 47, 0, 0, 415, 24, 1, 0, 0, 0, 416, 417, 5, 37, 0, 0, 417,\n\t\t26, 1, 0, 0, 0, 418, 419, 5, 60, 0, 0, 419, 420, 5, 60, 0, 0, 420, 28,\n\t\t1, 0, 0, 0, 421, 422, 5, 62, 0, 0, 422, 423, 5, 62, 0, 0, 423, 30, 1, 0,\n\t\t0, 0, 424, 425, 5, 38, 0, 0, 425, 32, 1, 0, 0, 0, 426, 427, 5, 124, 0,\n\t\t0, 427, 34, 1, 0, 0, 0, 428, 429, 5, 60, 0, 0, 429, 36, 1, 0, 0, 0, 430,\n\t\t431, 5, 60, 0, 0, 431, 432, 5, 61, 0, 0, 432, 38, 1, 0, 0, 0, 433, 434,\n\t\t5, 62, 0, 0, 434, 40, 1, 0, 0, 0, 435, 436, 5, 62, 0, 0, 436, 437, 5, 61,\n\t\t0, 0, 437, 42, 1, 0, 0, 0, 438, 439, 5, 61, 0, 0, 439, 440, 5, 61, 0, 0,\n\t\t440, 44, 1, 0, 0, 0, 441, 442, 5, 33, 0, 0, 442, 443, 5, 61, 0, 0, 443,\n\t\t46, 1, 0, 0, 0, 444, 445, 5, 60, 0, 0, 445, 446, 5, 62, 0, 0, 446, 48,\n\t\t1, 0, 0, 0, 447, 448, 7, 0, 0, 0, 448, 449, 7, 1, 0, 0, 449, 450, 7, 2,\n\t\t0, 0, 450, 451, 7, 3, 0, 0, 451, 452, 7, 4, 0, 0, 452, 50, 1, 0, 0, 0,\n\t\t453, 454, 7, 0, 0, 0, 454, 455, 7, 5, 0, 0, 455, 456, 7, 4, 0, 0, 456,\n\t\t457, 7, 6, 0, 0, 457, 458, 7, 2, 0, 0, 458, 459, 7, 7, 0, 0, 459, 52, 1,\n\t\t0, 0, 0, 460, 461, 7, 0, 0, 0, 461, 462, 7, 8, 0, 0, 462, 463, 7, 8, 0,\n\t\t0, 463, 54, 1, 0, 0, 0, 464, 465, 7, 0, 0, 0, 465, 466, 7, 9, 0, 0, 466,\n\t\t467, 7, 4, 0, 0, 467, 468, 7, 10, 0, 0, 468, 469, 7, 3, 0, 0, 469, 56,\n\t\t1, 0, 0, 0, 470, 471, 7, 0, 0, 0, 471, 472, 7, 11, 0, 0, 472, 473, 7, 11,\n\t\t0, 0, 473, 58, 1, 0, 0, 0, 474, 475, 7, 0, 0, 0, 475, 476, 7, 11, 0, 0,\n\t\t476, 477, 7, 4, 0, 0, 477, 478, 7, 10, 0, 0, 478, 479, 7, 3, 0, 0, 479,\n\t\t60, 1, 0, 0, 0, 480, 481, 7, 0, 0, 0, 481, 482, 7, 7, 0, 0, 482, 483, 7,\n\t\t0, 0, 0, 483, 484, 7, 11, 0, 0, 484, 485, 7, 12, 0, 0, 485, 486, 7, 13,\n\t\t0, 0, 486, 487, 7, 10, 0, 0, 487, 62, 1, 0, 0, 0, 488, 489, 7, 0, 0, 0,\n\t\t489, 490, 7, 7, 0, 0, 490, 491, 7, 8, 0, 0, 491, 64, 1, 0, 0, 0, 492, 493,\n\t\t7, 0, 0, 0, 493, 494, 7, 14, 0, 0, 494, 66, 1, 0, 0, 0, 495, 496, 7, 0,\n\t\t0, 0, 496, 497, 7, 14, 0, 0, 497, 498, 7, 5, 0, 0, 498, 68, 1, 0, 0, 0,\n\t\t499, 500, 7, 0, 0, 0, 500, 501, 7, 4, 0, 0, 501, 502, 7, 4, 0, 0, 502,\n\t\t503, 7, 0, 0, 0, 503, 504, 7, 5, 0, 0, 504, 505, 7, 15, 0, 0, 505, 70,\n\t\t1, 0, 0, 0, 506, 507, 7, 0, 0, 0, 507, 508, 7, 16, 0, 0, 508, 509, 7, 4,\n\t\t0, 0, 509, 510, 7, 2, 0, 0, 510, 511, 7, 6, 0, 0, 511, 512, 7, 7, 0, 0,\n\t\t512, 513, 7, 5, 0, 0, 513, 514, 7, 3, 0, 0, 514, 515, 7, 10, 0, 0, 515,\n\t\t516, 7, 17, 0, 0, 516, 517, 7, 10, 0, 0, 517, 518, 7, 7, 0, 0, 518, 519,\n\t\t7, 4, 0, 0, 519, 72, 1, 0, 0, 0, 520, 521, 7, 1, 0, 0, 521, 522, 7, 10,\n\t\t0, 0, 522, 523, 7, 9, 0, 0, 523, 524, 7, 2, 0, 0, 524, 525, 7, 3, 0, 0,\n\t\t525, 526, 7, 10, 0, 0, 526, 74, 1, 0, 0, 0, 527, 528, 7, 1, 0, 0, 528,\n\t\t529, 7, 10, 0, 0, 529, 530, 7, 18, 0, 0, 530, 531, 7, 6, 0, 0, 531, 532,\n\t\t7, 7, 0, 0, 532, 76, 1, 0, 0, 0, 533, 534, 7, 1, 0, 0, 534, 535, 7, 10,\n\t\t0, 0, 535, 536, 7, 4, 0, 0, 536, 537, 7, 19, 0, 0, 537, 538, 7, 10, 0,\n\t\t0, 538, 539, 7, 10, 0, 0, 539, 540, 7, 7, 0, 0, 540, 78, 1, 0, 0, 0, 541,\n\t\t542, 7, 1, 0, 0, 542, 543, 7, 12, 0, 0, 543, 80, 1, 0, 0, 0, 544, 545,\n\t\t7, 5, 0, 0, 545, 546, 7, 0, 0, 0, 546, 547, 7, 14, 0, 0, 547, 548, 7, 5,\n\t\t0, 0, 548, 549, 7, 0, 0, 0, 549, 550, 7, 8, 0, 0, 550, 551, 7, 10, 0, 0,\n\t\t551, 82, 1, 0, 0, 0, 552, 553, 7, 5, 0, 0, 553, 554, 7, 0, 0, 0, 554, 555,\n\t\t7, 14, 0, 0, 555, 556, 7, 10, 0, 0, 556, 84, 1, 0, 0, 0, 557, 558, 7, 5,\n\t\t0, 0, 558, 559, 7, 0, 0, 0, 559, 560, 7, 14, 0, 0, 560, 561, 7, 4, 0, 0,\n\t\t561, 86, 1, 0, 0, 0, 562, 563, 7, 5, 0, 0, 563, 564, 7, 15, 0, 0, 564,\n\t\t565, 7, 10, 0, 0, 565, 566, 7, 5, 0, 0, 566, 567, 7, 20, 0, 0, 567, 88,\n\t\t1, 0, 0, 0, 568, 569, 7, 5, 0, 0, 569, 570, 7, 2, 0, 0, 570, 571, 7, 11,\n\t\t0, 0, 571, 572, 7, 11, 0, 0, 572, 573, 7, 0, 0, 0, 573, 574, 7, 4, 0, 0,\n\t\t574, 575, 7, 10, 0, 0, 575, 90, 1, 0, 0, 0, 576, 577, 7, 5, 0, 0, 577,\n\t\t578, 7, 2, 0, 0, 578, 579, 7, 11, 0, 0, 579, 580, 7, 16, 0, 0, 580, 581,\n\t\t7, 17, 0, 0, 581, 582, 7, 7, 0, 0, 582, 92, 1, 0, 0, 0, 583, 584, 7, 5,\n\t\t0, 0, 584, 585, 7, 2, 0, 0, 585, 586, 7, 17, 0, 0, 586, 587, 7, 17, 0,\n\t\t0, 587, 588, 7, 6, 0, 0, 588, 589, 7, 4, 0, 0, 589, 94, 1, 0, 0, 0, 590,\n\t\t591, 7, 5, 0, 0, 591, 592, 7, 2, 0, 0, 592, 593, 7, 7, 0, 0, 593, 594,\n\t\t7, 9, 0, 0, 594, 595, 7, 11, 0, 0, 595, 596, 7, 6, 0, 0, 596, 597, 7, 5,\n\t\t0, 0, 597, 598, 7, 4, 0, 0, 598, 96, 1, 0, 0, 0, 599, 600, 7, 5, 0, 0,\n\t\t600, 601, 7, 2, 0, 0, 601, 602, 7, 7, 0, 0, 602, 603, 7, 14, 0, 0, 603,\n\t\t604, 7, 4, 0, 0, 604, 605, 7, 3, 0, 0, 605, 606, 7, 0, 0, 0, 606, 607,\n\t\t7, 6, 0, 0, 607, 608, 7, 7, 0, 0, 608, 609, 7, 4, 0, 0, 609, 98, 1, 0,\n\t\t0, 0, 610, 611, 7, 5, 0, 0, 611, 612, 7, 3, 0, 0, 612, 613, 7, 10, 0, 0,\n\t\t613, 614, 7, 0, 0, 0, 614, 615, 7, 4, 0, 0, 615, 616, 7, 10, 0, 0, 616,\n\t\t100, 1, 0, 0, 0, 617, 618, 7, 5, 0, 0, 618, 619, 7, 3, 0, 0, 619, 620,\n\t\t7, 2, 0, 0, 620, 621, 7, 14, 0, 0, 621, 622, 7, 14, 0, 0, 622, 102, 1,\n\t\t0, 0, 0, 623, 624, 7, 5, 0, 0, 624, 625, 7, 16, 0, 0, 625, 626, 7, 3, 0,\n\t\t0, 626, 627, 7, 3, 0, 0, 627, 628, 7, 10, 0, 0, 628, 629, 7, 7, 0, 0, 629,\n\t\t630, 7, 4, 0, 0, 630, 631, 5, 95, 0, 0, 631, 632, 7, 8, 0, 0, 632, 633,\n\t\t7, 0, 0, 0, 633, 634, 7, 4, 0, 0, 634, 635, 7, 10, 0, 0, 635, 104, 1, 0,\n\t\t0, 0, 636, 637, 7, 5, 0, 0, 637, 638, 7, 16, 0, 0, 638, 639, 7, 3, 0, 0,\n\t\t639, 640, 7, 3, 0, 0, 640, 641, 7, 10, 0, 0, 641, 642, 7, 7, 0, 0, 642,\n\t\t643, 7, 4, 0, 0, 643, 644, 5, 95, 0, 0, 644, 645, 7, 4, 0, 0, 645, 646,\n\t\t7, 6, 0, 0, 646, 647, 7, 17, 0, 0, 647, 648, 7, 10, 0, 0, 648, 106, 1,\n\t\t0, 0, 0, 649, 650, 7, 5, 0, 0, 650, 651, 7, 16, 0, 0, 651, 652, 7, 3, 0,\n\t\t0, 652, 653, 7, 3, 0, 0, 653, 654, 7, 10, 0, 0, 654, 655, 7, 7, 0, 0, 655,\n\t\t656, 7, 4, 0, 0, 656, 657, 5, 95, 0, 0, 657, 658, 7, 4, 0, 0, 658, 659,\n\t\t7, 6, 0, 0, 659, 660, 7, 17, 0, 0, 660, 661, 7, 10, 0, 0, 661, 662, 7,\n\t\t14, 0, 0, 662, 663, 7, 4, 0, 0, 663, 664, 7, 0, 0, 0, 664, 665, 7, 17,\n\t\t0, 0, 665, 666, 7, 21, 0, 0, 666, 108, 1, 0, 0, 0, 667, 668, 7, 8, 0, 0,\n\t\t668, 669, 7, 0, 0, 0, 669, 670, 7, 4, 0, 0, 670, 671, 7, 0, 0, 0, 671,\n\t\t672, 7, 1, 0, 0, 672, 673, 7, 0, 0, 0, 673, 674, 7, 14, 0, 0, 674, 675,\n\t\t7, 10, 0, 0, 675, 110, 1, 0, 0, 0, 676, 677, 7, 8, 0, 0, 677, 678, 7, 10,\n\t\t0, 0, 678, 679, 7, 9, 0, 0, 679, 680, 7, 0, 0, 0, 680, 681, 7, 16, 0, 0,\n\t\t681, 682, 7, 11, 0, 0, 682, 683, 7, 4, 0, 0, 683, 112, 1, 0, 0, 0, 684,\n\t\t685, 7, 8, 0, 0, 685, 686, 7, 10, 0, 0, 686, 687, 7, 9, 0, 0, 687, 688,\n\t\t7, 10, 0, 0, 688, 689, 7, 3, 0, 0, 689, 690, 7, 3, 0, 0, 690, 691, 7, 0,\n\t\t0, 0, 691, 692, 7, 1, 0, 0, 692, 693, 7, 11, 0, 0, 693, 694, 7, 10, 0,\n\t\t0, 694, 114, 1, 0, 0, 0, 695, 696, 7, 8, 0, 0, 696, 697, 7, 10, 0, 0, 697,\n\t\t698, 7, 9, 0, 0, 698, 699, 7, 10, 0, 0, 699, 700, 7, 3, 0, 0, 700, 701,\n\t\t7, 3, 0, 0, 701, 702, 7, 10, 0, 0, 702, 703, 7, 8, 0, 0, 703, 116, 1, 0,\n\t\t0, 0, 704, 705, 7, 8, 0, 0, 705, 706, 7, 10, 0, 0, 706, 707, 7, 11, 0,\n\t\t0, 707, 708, 7, 10, 0, 0, 708, 709, 7, 4, 0, 0, 709, 710, 7, 10, 0, 0,\n\t\t710, 118, 1, 0, 0, 0, 711, 712, 7, 8, 0, 0, 712, 713, 7, 10, 0, 0, 713,\n\t\t714, 7, 14, 0, 0, 714, 715, 7, 5, 0, 0, 715, 120, 1, 0, 0, 0, 716, 717,\n\t\t7, 8, 0, 0, 717, 718, 7, 10, 0, 0, 718, 719, 7, 4, 0, 0, 719, 720, 7, 0,\n\t\t0, 0, 720, 721, 7, 5, 0, 0, 721, 722, 7, 15, 0, 0, 722, 122, 1, 0, 0, 0,\n\t\t723, 724, 7, 8, 0, 0, 724, 725, 7, 6, 0, 0, 725, 726, 7, 14, 0, 0, 726,\n\t\t727, 7, 4, 0, 0, 727, 728, 7, 6, 0, 0, 728, 729, 7, 7, 0, 0, 729, 730,\n\t\t7, 5, 0, 0, 730, 731, 7, 4, 0, 0, 731, 124, 1, 0, 0, 0, 732, 733, 7, 8,\n\t\t0, 0, 733, 734, 7, 3, 0, 0, 734, 735, 7, 2, 0, 0, 735, 736, 7, 21, 0, 0,\n\t\t736, 126, 1, 0, 0, 0, 737, 738, 7, 10, 0, 0, 738, 739, 7, 0, 0, 0, 739,\n\t\t740, 7, 5, 0, 0, 740, 741, 7, 15, 0, 0, 741, 128, 1, 0, 0, 0, 742, 743,\n\t\t7, 10, 0, 0, 743, 744, 7, 11, 0, 0, 744, 745, 7, 14, 0, 0, 745, 746, 7,\n\t\t10, 0, 0, 746, 130, 1, 0, 0, 0, 747, 748, 7, 10, 0, 0, 748, 749, 7, 7,\n\t\t0, 0, 749, 750, 7, 8, 0, 0, 750, 132, 1, 0, 0, 0, 751, 752, 7, 10, 0, 0,\n\t\t752, 753, 7, 14, 0, 0, 753, 754, 7, 5, 0, 0, 754, 755, 7, 0, 0, 0, 755,\n\t\t756, 7, 21, 0, 0, 756, 757, 7, 10, 0, 0, 757, 134, 1, 0, 0, 0, 758, 759,\n\t\t7, 10, 0, 0, 759, 760, 7, 22, 0, 0, 760, 761, 7, 5, 0, 0, 761, 762, 7,\n\t\t10, 0, 0, 762, 763, 7, 21, 0, 0, 763, 764, 7, 4, 0, 0, 764, 136, 1, 0,\n\t\t0, 0, 765, 766, 7, 10, 0, 0, 766, 767, 7, 22, 0, 0, 767, 768, 7, 5, 0,\n\t\t0, 768, 769, 7, 11, 0, 0, 769, 770, 7, 16, 0, 0, 770, 771, 7, 14, 0, 0,\n\t\t771, 772, 7, 6, 0, 0, 772, 773, 7, 23, 0, 0, 773, 774, 7, 10, 0, 0, 774,\n\t\t138, 1, 0, 0, 0, 775, 776, 7, 10, 0, 0, 776, 777, 7, 22, 0, 0, 777, 778,\n\t\t7, 6, 0, 0, 778, 779, 7, 14, 0, 0, 779, 780, 7, 4, 0, 0, 780, 781, 7, 14,\n\t\t0, 0, 781, 140, 1, 0, 0, 0, 782, 783, 7, 10, 0, 0, 783, 784, 7, 22, 0,\n\t\t0, 784, 785, 7, 21, 0, 0, 785, 786, 7, 11, 0, 0, 786, 787, 7, 0, 0, 0,\n\t\t787, 788, 7, 6, 0, 0, 788, 789, 7, 7, 0, 0, 789, 142, 1, 0, 0, 0, 790,\n\t\t791, 7, 9, 0, 0, 791, 792, 7, 0, 0, 0, 792, 793, 7, 6, 0, 0, 793, 794,\n\t\t7, 11, 0, 0, 794, 144, 1, 0, 0, 0, 795, 796, 7, 9, 0, 0, 796, 797, 7, 2,\n\t\t0, 0, 797, 798, 7, 3, 0, 0, 798, 146, 1, 0, 0, 0, 799, 800, 7, 9, 0, 0,\n\t\t800, 801, 7, 2, 0, 0, 801, 802, 7, 3, 0, 0, 802, 803, 7, 10, 0, 0, 803,\n\t\t804, 7, 6, 0, 0, 804, 805, 7, 18, 0, 0, 805, 806, 7, 7, 0, 0, 806, 148,\n\t\t1, 0, 0, 0, 807, 808, 7, 9, 0, 0, 808, 809, 7, 3, 0, 0, 809, 810, 7, 2,\n\t\t0, 0, 810, 811, 7, 17, 0, 0, 811, 150, 1, 0, 0, 0, 812, 813, 7, 9, 0, 0,\n\t\t813, 814, 7, 16, 0, 0, 814, 815, 7, 11, 0, 0, 815, 816, 7, 11, 0, 0, 816,\n\t\t152, 1, 0, 0, 0, 817, 818, 7, 18, 0, 0, 818, 819, 7, 11, 0, 0, 819, 820,\n\t\t7, 2, 0, 0, 820, 821, 7, 1, 0, 0, 821, 154, 1, 0, 0, 0, 822, 823, 7, 18,\n\t\t0, 0, 823, 824, 7, 3, 0, 0, 824, 825, 7, 2, 0, 0, 825, 826, 7, 16, 0, 0,\n\t\t826, 827, 7, 21, 0, 0, 827, 156, 1, 0, 0, 0, 828, 829, 7, 15, 0, 0, 829,\n\t\t830, 7, 0, 0, 0, 830, 831, 7, 23, 0, 0, 831, 832, 7, 6, 0, 0, 832, 833,\n\t\t7, 7, 0, 0, 833, 834, 7, 18, 0, 0, 834, 158, 1, 0, 0, 0, 835, 836, 7, 6,\n\t\t0, 0, 836, 837, 7, 9, 0, 0, 837, 160, 1, 0, 0, 0, 838, 839, 7, 6, 0, 0,\n\t\t839, 840, 7, 18, 0, 0, 840, 841, 7, 7, 0, 0, 841, 842, 7, 2, 0, 0, 842,\n\t\t843, 7, 3, 0, 0, 843, 844, 7, 10, 0, 0, 844, 162, 1, 0, 0, 0, 845, 846,\n\t\t7, 6, 0, 0, 846, 847, 7, 17, 0, 0, 847, 848, 7, 17, 0, 0, 848, 849, 7,\n\t\t10, 0, 0, 849, 850, 7, 8, 0, 0, 850, 851, 7, 6, 0, 0, 851, 852, 7, 0, 0,\n\t\t0, 852, 853, 7, 4, 0, 0, 853, 854, 7, 10, 0, 0, 854, 164, 1, 0, 0, 0, 855,\n\t\t856, 7, 6, 0, 0, 856, 857, 7, 7, 0, 0, 857, 166, 1, 0, 0, 0, 858, 859,\n\t\t7, 6, 0, 0, 859, 860, 7, 7, 0, 0, 860, 861, 7, 8, 0, 0, 861, 862, 7, 10,\n\t\t0, 0, 862, 863, 7, 22, 0, 0, 863, 168, 1, 0, 0, 0, 864, 865, 7, 6, 0, 0,\n\t\t865, 866, 7, 7, 0, 0, 866, 867, 7, 8, 0, 0, 867, 868, 7, 10, 0, 0, 868,\n\t\t869, 7, 22, 0, 0, 869, 870, 7, 10, 0, 0, 870, 871, 7, 8, 0, 0, 871, 170,\n\t\t1, 0, 0, 0, 872, 873, 7, 6, 0, 0, 873, 874, 7, 7, 0, 0, 874, 875, 7, 6,\n\t\t0, 0, 875, 876, 7, 4, 0, 0, 876, 877, 7, 6, 0, 0, 877, 878, 7, 0, 0, 0,\n\t\t878, 879, 7, 11, 0, 0, 879, 880, 7, 11, 0, 0, 880, 881, 7, 12, 0, 0, 881,\n\t\t172, 1, 0, 0, 0, 882, 883, 7, 6, 0, 0, 883, 884, 7, 7, 0, 0, 884, 885,\n\t\t7, 7, 0, 0, 885, 886, 7, 10, 0, 0, 886, 887, 7, 3, 0, 0, 887, 174, 1, 0,\n\t\t0, 0, 888, 889, 7, 6, 0, 0, 889, 890, 7, 7, 0, 0, 890, 891, 7, 14, 0, 0,\n\t\t891, 892, 7, 10, 0, 0, 892, 893, 7, 3, 0, 0, 893, 894, 7, 4, 0, 0, 894,\n\t\t176, 1, 0, 0, 0, 895, 896, 7, 6, 0, 0, 896, 897, 7, 7, 0, 0, 897, 898,\n\t\t7, 14, 0, 0, 898, 899, 7, 4, 0, 0, 899, 900, 7, 10, 0, 0, 900, 901, 7,\n\t\t0, 0, 0, 901, 902, 7, 8, 0, 0, 902, 178, 1, 0, 0, 0, 903, 904, 7, 6, 0,\n\t\t0, 904, 905, 7, 7, 0, 0, 905, 906, 7, 4, 0, 0, 906, 907, 7, 10, 0, 0, 907,\n\t\t908, 7, 3, 0, 0, 908, 909, 7, 14, 0, 0, 909, 910, 7, 10, 0, 0, 910, 911,\n\t\t7, 5, 0, 0, 911, 912, 7, 4, 0, 0, 912, 180, 1, 0, 0, 0, 913, 914, 7, 6,\n\t\t0, 0, 914, 915, 7, 7, 0, 0, 915, 916, 7, 4, 0, 0, 916, 917, 7, 2, 0, 0,\n\t\t917, 182, 1, 0, 0, 0, 918, 919, 7, 6, 0, 0, 919, 920, 7, 14, 0, 0, 920,\n\t\t184, 1, 0, 0, 0, 921, 922, 7, 6, 0, 0, 922, 923, 7, 14, 0, 0, 923, 924,\n\t\t7, 7, 0, 0, 924, 925, 7, 16, 0, 0, 925, 926, 7, 11, 0, 0, 926, 927, 7,\n\t\t11, 0, 0, 927, 186, 1, 0, 0, 0, 928, 929, 7, 24, 0, 0, 929, 930, 7, 2,\n\t\t0, 0, 930, 931, 7, 6, 0, 0, 931, 932, 7, 7, 0, 0, 932, 188, 1, 0, 0, 0,\n\t\t933, 934, 7, 20, 0, 0, 934, 935, 7, 10, 0, 0, 935, 936, 7, 12, 0, 0, 936,\n\t\t190, 1, 0, 0, 0, 937, 938, 7, 11, 0, 0, 938, 939, 7, 10, 0, 0, 939, 940,\n\t\t7, 9, 0, 0, 940, 941, 7, 4, 0, 0, 941, 192, 1, 0, 0, 0, 942, 943, 7, 11,\n\t\t0, 0, 943, 944, 7, 6, 0, 0, 944, 945, 7, 20, 0, 0, 945, 946, 7, 10, 0,\n\t\t0, 946, 194, 1, 0, 0, 0, 947, 948, 7, 11, 0, 0, 948, 949, 7, 6, 0, 0, 949,\n\t\t950, 7, 17, 0, 0, 950, 951, 7, 6, 0, 0, 951, 952, 7, 4, 0, 0, 952, 196,\n\t\t1, 0, 0, 0, 953, 954, 7, 17, 0, 0, 954, 955, 7, 0, 0, 0, 955, 956, 7, 4,\n\t\t0, 0, 956, 957, 7, 5, 0, 0, 957, 958, 7, 15, 0, 0, 958, 198, 1, 0, 0, 0,\n\t\t959, 960, 7, 7, 0, 0, 960, 961, 7, 0, 0, 0, 961, 962, 7, 4, 0, 0, 962,\n\t\t963, 7, 16, 0, 0, 963, 964, 7, 3, 0, 0, 964, 965, 7, 0, 0, 0, 965, 966,\n\t\t7, 11, 0, 0, 966, 200, 1, 0, 0, 0, 967, 968, 7, 7, 0, 0, 968, 969, 7, 2,\n\t\t0, 0, 969, 202, 1, 0, 0, 0, 970, 971, 7, 7, 0, 0, 971, 972, 7, 2, 0, 0,\n\t\t972, 973, 7, 4, 0, 0, 973, 204, 1, 0, 0, 0, 974, 975, 7, 7, 0, 0, 975,\n\t\t976, 7, 2, 0, 0, 976, 977, 7, 4, 0, 0, 977, 978, 7, 7, 0, 0, 978, 979,\n\t\t7, 16, 0, 0, 979, 980, 7, 11, 0, 0, 980, 981, 7, 11, 0, 0, 981, 206, 1,\n\t\t0, 0, 0, 982, 983, 7, 7, 0, 0, 983, 984, 7, 16, 0, 0, 984, 985, 7, 11,\n\t\t0, 0, 985, 986, 7, 11, 0, 0, 986, 208, 1, 0, 0, 0, 987, 988, 7, 2, 0, 0,\n\t\t988, 989, 7, 9, 0, 0, 989, 210, 1, 0, 0, 0, 990, 991, 7, 2, 0, 0, 991,\n\t\t992, 7, 9, 0, 0, 992, 993, 7, 9, 0, 0, 993, 994, 7, 14, 0, 0, 994, 995,\n\t\t7, 10, 0, 0, 995, 996, 7, 4, 0, 0, 996, 212, 1, 0, 0, 0, 997, 998, 7, 2,\n\t\t0, 0, 998, 999, 7, 7, 0, 0, 999, 214, 1, 0, 0, 0, 1000, 1001, 7, 2, 0,\n\t\t0, 1001, 1002, 7, 3, 0, 0, 1002, 216, 1, 0, 0, 0, 1003, 1004, 7, 2, 0,\n\t\t0, 1004, 1005, 7, 3, 0, 0, 1005, 1006, 7, 8, 0, 0, 1006, 1007, 7, 10, 0,\n\t\t0, 1007, 1008, 7, 3, 0, 0, 1008, 218, 1, 0, 0, 0, 1009, 1010, 7, 2, 0,\n\t\t0, 1010, 1011, 7, 16, 0, 0, 1011, 1012, 7, 4, 0, 0, 1012, 1013, 7, 10,\n\t\t0, 0, 1013, 1014, 7, 3, 0, 0, 1014, 220, 1, 0, 0, 0, 1015, 1016, 7, 21,\n\t\t0, 0, 1016, 1017, 7, 11, 0, 0, 1017, 1018, 7, 0, 0, 0, 1018, 1019, 7, 7,\n\t\t0, 0, 1019, 222, 1, 0, 0, 0, 1020, 1021, 7, 21, 0, 0, 1021, 1022, 7, 3,\n\t\t0, 0, 1022, 1023, 7, 0, 0, 0, 1023, 1024, 7, 18, 0, 0, 1024, 1025, 7, 17,\n\t\t0, 0, 1025, 1026, 7, 0, 0, 0, 1026, 224, 1, 0, 0, 0, 1027, 1028, 7, 21,\n\t\t0, 0, 1028, 1029, 7, 3, 0, 0, 1029, 1030, 7, 6, 0, 0, 1030, 1031, 7, 17,\n\t\t0, 0, 1031, 1032, 7, 0, 0, 0, 1032, 1033, 7, 3, 0, 0, 1033, 1034, 7, 12,\n\t\t0, 0, 1034, 226, 1, 0, 0, 0, 1035, 1036, 7, 25, 0, 0, 1036, 1037, 7, 16,\n\t\t0, 0, 1037, 1038, 7, 10, 0, 0, 1038, 1039, 7, 3, 0, 0, 1039, 1040, 7, 12,\n\t\t0, 0, 1040, 228, 1, 0, 0, 0, 1041, 1042, 7, 3, 0, 0, 1042, 1043, 7, 0,\n\t\t0, 0, 1043, 1044, 7, 6, 0, 0, 1044, 1045, 7, 14, 0, 0, 1045, 1046, 7, 10,\n\t\t0, 0, 1046, 230, 1, 0, 0, 0, 1047, 1048, 7, 3, 0, 0, 1048, 1049, 7, 10,\n\t\t0, 0, 1049, 1050, 7, 5, 0, 0, 1050, 1051, 7, 16, 0, 0, 1051, 1052, 7, 3,\n\t\t0, 0, 1052, 1053, 7, 14, 0, 0, 1053, 1054, 7, 6, 0, 0, 1054, 1055, 7, 23,\n\t\t0, 0, 1055, 1056, 7, 10, 0, 0, 1056, 232, 1, 0, 0, 0, 1057, 1058, 7, 3,\n\t\t0, 0, 1058, 1059, 7, 10, 0, 0, 1059, 1060, 7, 9, 0, 0, 1060, 1061, 7, 10,\n\t\t0, 0, 1061, 1062, 7, 3, 0, 0, 1062, 1063, 7, 10, 0, 0, 1063, 1064, 7, 7,\n\t\t0, 0, 1064, 1065, 7, 5, 0, 0, 1065, 1066, 7, 10, 0, 0, 1066, 1067, 7, 14,\n\t\t0, 0, 1067, 234, 1, 0, 0, 0, 1068, 1069, 7, 3, 0, 0, 1069, 1070, 7, 10,\n\t\t0, 0, 1070, 1071, 7, 18, 0, 0, 1071, 1072, 7, 10, 0, 0, 1072, 1073, 7,\n\t\t22, 0, 0, 1073, 1074, 7, 21, 0, 0, 1074, 236, 1, 0, 0, 0, 1075, 1076, 7,\n\t\t3, 0, 0, 1076, 1077, 7, 10, 0, 0, 1077, 1078, 7, 6, 0, 0, 1078, 1079, 7,\n\t\t7, 0, 0, 1079, 1080, 7, 8, 0, 0, 1080, 1081, 7, 10, 0, 0, 1081, 1082, 7,\n\t\t22, 0, 0, 1082, 238, 1, 0, 0, 0, 1083, 1084, 7, 3, 0, 0, 1084, 1085, 7,\n\t\t10, 0, 0, 1085, 1086, 7, 11, 0, 0, 1086, 1087, 7, 10, 0, 0, 1087, 1088,\n\t\t7, 0, 0, 0, 1088, 1089, 7, 14, 0, 0, 1089, 1090, 7, 10, 0, 0, 1090, 240,\n\t\t1, 0, 0, 0, 1091, 1092, 7, 3, 0, 0, 1092, 1093, 7, 10, 0, 0, 1093, 1094,\n\t\t7, 7, 0, 0, 1094, 1095, 7, 0, 0, 0, 1095, 1096, 7, 17, 0, 0, 1096, 1097,\n\t\t7, 10, 0, 0, 1097, 242, 1, 0, 0, 0, 1098, 1099, 7, 3, 0, 0, 1099, 1100,\n\t\t7, 10, 0, 0, 1100, 1101, 7, 21, 0, 0, 1101, 1102, 7, 11, 0, 0, 1102, 1103,\n\t\t7, 0, 0, 0, 1103, 1104, 7, 5, 0, 0, 1104, 1105, 7, 10, 0, 0, 1105, 244,\n\t\t1, 0, 0, 0, 1106, 1107, 7, 3, 0, 0, 1107, 1108, 7, 10, 0, 0, 1108, 1109,\n\t\t7, 14, 0, 0, 1109, 1110, 7, 4, 0, 0, 1110, 1111, 7, 3, 0, 0, 1111, 1112,\n\t\t7, 6, 0, 0, 1112, 1113, 7, 5, 0, 0, 1113, 1114, 7, 4, 0, 0, 1114, 246,\n\t\t1, 0, 0, 0, 1115, 1116, 7, 3, 0, 0, 1116, 1117, 7, 10, 0, 0, 1117, 1118,\n\t\t7, 4, 0, 0, 1118, 1119, 7, 16, 0, 0, 1119, 1120, 7, 3, 0, 0, 1120, 1121,\n\t\t7, 7, 0, 0, 1121, 1122, 7, 6, 0, 0, 1122, 1123, 7, 7, 0, 0, 1123, 1124,\n\t\t7, 18, 0, 0, 1124, 248, 1, 0, 0, 0, 1125, 1126, 7, 3, 0, 0, 1126, 1127,\n\t\t7, 6, 0, 0, 1127, 1128, 7, 18, 0, 0, 1128, 1129, 7, 15, 0, 0, 1129, 1130,\n\t\t7, 4, 0, 0, 1130, 250, 1, 0, 0, 0, 1131, 1132, 7, 3, 0, 0, 1132, 1133,\n\t\t7, 2, 0, 0, 1133, 1134, 7, 11, 0, 0, 1134, 1135, 7, 11, 0, 0, 1135, 1136,\n\t\t7, 1, 0, 0, 1136, 1137, 7, 0, 0, 0, 1137, 1138, 7, 5, 0, 0, 1138, 1139,\n\t\t7, 20, 0, 0, 1139, 252, 1, 0, 0, 0, 1140, 1141, 7, 3, 0, 0, 1141, 1142,\n\t\t7, 2, 0, 0, 1142, 1143, 7, 19, 0, 0, 1143, 254, 1, 0, 0, 0, 1144, 1145,\n\t\t7, 3, 0, 0, 1145, 1146, 7, 2, 0, 0, 1146, 1147, 7, 19, 0, 0, 1147, 1148,\n\t\t7, 14, 0, 0, 1148, 256, 1, 0, 0, 0, 1149, 1150, 7, 14, 0, 0, 1150, 1151,\n\t\t7, 0, 0, 0, 1151, 1152, 7, 23, 0, 0, 1152, 1153, 7, 10, 0, 0, 1153, 1154,\n\t\t7, 21, 0, 0, 1154, 1155, 7, 2, 0, 0, 1155, 1156, 7, 6, 0, 0, 1156, 1157,\n\t\t7, 7, 0, 0, 1157, 1158, 7, 4, 0, 0, 1158, 258, 1, 0, 0, 0, 1159, 1160,\n\t\t7, 14, 0, 0, 1160, 1161, 7, 10, 0, 0, 1161, 1162, 7, 11, 0, 0, 1162, 1163,\n\t\t7, 10, 0, 0, 1163, 1164, 7, 5, 0, 0, 1164, 1165, 7, 4, 0, 0, 1165, 260,\n\t\t1, 0, 0, 0, 1166, 1167, 7, 14, 0, 0, 1167, 1168, 7, 10, 0, 0, 1168, 1169,\n\t\t7, 4, 0, 0, 1169, 262, 1, 0, 0, 0, 1170, 1171, 7, 4, 0, 0, 1171, 1172,\n\t\t7, 0, 0, 0, 1172, 1173, 7, 1, 0, 0, 1173, 1174, 7, 11, 0, 0, 1174, 1175,\n\t\t7, 10, 0, 0, 1175, 264, 1, 0, 0, 0, 1176, 1177, 7, 4, 0, 0, 1177, 1178,\n\t\t7, 10, 0, 0, 1178, 1179, 7, 17, 0, 0, 1179, 1180, 7, 21, 0, 0, 1180, 266,\n\t\t1, 0, 0, 0, 1181, 1182, 7, 4, 0, 0, 1182, 1183, 7, 10, 0, 0, 1183, 1184,\n\t\t7, 17, 0, 0, 1184, 1185, 7, 21, 0, 0, 1185, 1186, 7, 2, 0, 0, 1186, 1187,\n\t\t7, 3, 0, 0, 1187, 1188, 7, 0, 0, 0, 1188, 1189, 7, 3, 0, 0, 1189, 1190,\n\t\t7, 12, 0, 0, 1190, 268, 1, 0, 0, 0, 1191, 1192, 7, 4, 0, 0, 1192, 1193,\n\t\t7, 15, 0, 0, 1193, 1194, 7, 10, 0, 0, 1194, 1195, 7, 7, 0, 0, 1195, 270,\n\t\t1, 0, 0, 0, 1196, 1197, 7, 4, 0, 0, 1197, 1198, 7, 2, 0, 0, 1198, 272,\n\t\t1, 0, 0, 0, 1199, 1200, 7, 4, 0, 0, 1200, 1201, 7, 3, 0, 0, 1201, 1202,\n\t\t7, 0, 0, 0, 1202, 1203, 7, 7, 0, 0, 1203, 1204, 7, 14, 0, 0, 1204, 1205,\n\t\t7, 0, 0, 0, 1205, 1206, 7, 5, 0, 0, 1206, 1207, 7, 4, 0, 0, 1207, 1208,\n\t\t7, 6, 0, 0, 1208, 1209, 7, 2, 0, 0, 1209, 1210, 7, 7, 0, 0, 1210, 274,\n\t\t1, 0, 0, 0, 1211, 1212, 7, 4, 0, 0, 1212, 1213, 7, 3, 0, 0, 1213, 1214,\n\t\t7, 6, 0, 0, 1214, 1215, 7, 18, 0, 0, 1215, 1216, 7, 18, 0, 0, 1216, 1217,\n\t\t7, 10, 0, 0, 1217, 1218, 7, 3, 0, 0, 1218, 276, 1, 0, 0, 0, 1219, 1220,\n\t\t7, 16, 0, 0, 1220, 1221, 7, 7, 0, 0, 1221, 1222, 7, 6, 0, 0, 1222, 1223,\n\t\t7, 2, 0, 0, 1223, 1224, 7, 7, 0, 0, 1224, 278, 1, 0, 0, 0, 1225, 1226,\n\t\t7, 16, 0, 0, 1226, 1227, 7, 7, 0, 0, 1227, 1228, 7, 6, 0, 0, 1228, 1229,\n\t\t7, 25, 0, 0, 1229, 1230, 7, 16, 0, 0, 1230, 1231, 7, 10, 0, 0, 1231, 280,\n\t\t1, 0, 0, 0, 1232, 1233, 7, 16, 0, 0, 1233, 1234, 7, 21, 0, 0, 1234, 1235,\n\t\t7, 8, 0, 0, 1235, 1236, 7, 0, 0, 0, 1236, 1237, 7, 4, 0, 0, 1237, 1238,\n\t\t7, 10, 0, 0, 1238, 282, 1, 0, 0, 0, 1239, 1240, 7, 16, 0, 0, 1240, 1241,\n\t\t7, 14, 0, 0, 1241, 1242, 7, 6, 0, 0, 1242, 1243, 7, 7, 0, 0, 1243, 1244,\n\t\t7, 18, 0, 0, 1244, 284, 1, 0, 0, 0, 1245, 1246, 7, 23, 0, 0, 1246, 1247,\n\t\t7, 0, 0, 0, 1247, 1248, 7, 5, 0, 0, 1248, 1249, 7, 16, 0, 0, 1249, 1250,\n\t\t7, 16, 0, 0, 1250, 1251, 7, 17, 0, 0, 1251, 286, 1, 0, 0, 0, 1252, 1253,\n\t\t7, 23, 0, 0, 1253, 1254, 7, 0, 0, 0, 1254, 1255, 7, 11, 0, 0, 1255, 1256,\n\t\t7, 16, 0, 0, 1256, 1257, 7, 10, 0, 0, 1257, 1258, 7, 14, 0, 0, 1258, 288,\n\t\t1, 0, 0, 0, 1259, 1260, 7, 23, 0, 0, 1260, 1261, 7, 6, 0, 0, 1261, 1262,\n\t\t7, 10, 0, 0, 1262, 1263, 7, 19, 0, 0, 1263, 290, 1, 0, 0, 0, 1264, 1265,\n\t\t7, 23, 0, 0, 1265, 1266, 7, 6, 0, 0, 1266, 1267, 7, 3, 0, 0, 1267, 1268,\n\t\t7, 4, 0, 0, 1268, 1269, 7, 16, 0, 0, 1269, 1270, 7, 0, 0, 0, 1270, 1271,\n\t\t7, 11, 0, 0, 1271, 292, 1, 0, 0, 0, 1272, 1273, 7, 19, 0, 0, 1273, 1274,\n\t\t7, 15, 0, 0, 1274, 1275, 7, 10, 0, 0, 1275, 1276, 7, 7, 0, 0, 1276, 294,\n\t\t1, 0, 0, 0, 1277, 1278, 7, 19, 0, 0, 1278, 1279, 7, 15, 0, 0, 1279, 1280,\n\t\t7, 10, 0, 0, 1280, 1281, 7, 3, 0, 0, 1281, 1282, 7, 10, 0, 0, 1282, 296,\n\t\t1, 0, 0, 0, 1283, 1284, 7, 19, 0, 0, 1284, 1285, 7, 6, 0, 0, 1285, 1286,\n\t\t7, 4, 0, 0, 1286, 1287, 7, 15, 0, 0, 1287, 298, 1, 0, 0, 0, 1288, 1289,\n\t\t7, 19, 0, 0, 1289, 1290, 7, 6, 0, 0, 1290, 1291, 7, 4, 0, 0, 1291, 1292,\n\t\t7, 15, 0, 0, 1292, 1293, 7, 2, 0, 0, 1293, 1294, 7, 16, 0, 0, 1294, 1295,\n\t\t7, 4, 0, 0, 1295, 300, 1, 0, 0, 0, 1296, 1297, 7, 9, 0, 0, 1297, 1298,\n\t\t7, 6, 0, 0, 1298, 1299, 7, 3, 0, 0, 1299, 1300, 7, 14, 0, 0, 1300, 1301,\n\t\t7, 4, 0, 0, 1301, 1302, 5, 95, 0, 0, 1302, 1303, 7, 23, 0, 0, 1303, 1304,\n\t\t7, 0, 0, 0, 1304, 1305, 7, 11, 0, 0, 1305, 1306, 7, 16, 0, 0, 1306, 1307,\n\t\t7, 10, 0, 0, 1307, 302, 1, 0, 0, 0, 1308, 1309, 7, 2, 0, 0, 1309, 1310,\n\t\t7, 23, 0, 0, 1310, 1311, 7, 10, 0, 0, 1311, 1312, 7, 3, 0, 0, 1312, 304,\n\t\t1, 0, 0, 0, 1313, 1314, 7, 21, 0, 0, 1314, 1315, 7, 0, 0, 0, 1315, 1316,\n\t\t7, 3, 0, 0, 1316, 1317, 7, 4, 0, 0, 1317, 1318, 7, 6, 0, 0, 1318, 1319,\n\t\t7, 4, 0, 0, 1319, 1320, 7, 6, 0, 0, 1320, 1321, 7, 2, 0, 0, 1321, 1322,\n\t\t7, 7, 0, 0, 1322, 306, 1, 0, 0, 0, 1323, 1324, 7, 3, 0, 0, 1324, 1325,\n\t\t7, 0, 0, 0, 1325, 1326, 7, 7, 0, 0, 1326, 1327, 7, 18, 0, 0, 1327, 1328,\n\t\t7, 10, 0, 0, 1328, 308, 1, 0, 0, 0, 1329, 1330, 7, 21, 0, 0, 1330, 1331,\n\t\t7, 3, 0, 0, 1331, 1332, 7, 10, 0, 0, 1332, 1333, 7, 5, 0, 0, 1333, 1334,\n\t\t7, 10, 0, 0, 1334, 1335, 7, 8, 0, 0, 1335, 1336, 7, 6, 0, 0, 1336, 1337,\n\t\t7, 7, 0, 0, 1337, 1338, 7, 18, 0, 0, 1338, 310, 1, 0, 0, 0, 1339, 1340,\n\t\t7, 16, 0, 0, 1340, 1341, 7, 7, 0, 0, 1341, 1342, 7, 1, 0, 0, 1342, 1343,\n\t\t7, 2, 0, 0, 1343, 1344, 7, 16, 0, 0, 1344, 1345, 7, 7, 0, 0, 1345, 1346,\n\t\t7, 8, 0, 0, 1346, 1347, 7, 10, 0, 0, 1347, 1348, 7, 8, 0, 0, 1348, 312,\n\t\t1, 0, 0, 0, 1349, 1350, 7, 5, 0, 0, 1350, 1351, 7, 16, 0, 0, 1351, 1352,\n\t\t7, 3, 0, 0, 1352, 1353, 7, 3, 0, 0, 1353, 1354, 7, 10, 0, 0, 1354, 1355,\n\t\t7, 7, 0, 0, 1355, 1356, 7, 4, 0, 0, 1356, 314, 1, 0, 0, 0, 1357, 1358,\n\t\t7, 9, 0, 0, 1358, 1359, 7, 2, 0, 0, 1359, 1360, 7, 11, 0, 0, 1360, 1361,\n\t\t7, 11, 0, 0, 1361, 1362, 7, 2, 0, 0, 1362, 1363, 7, 19, 0, 0, 1363, 1364,\n\t\t7, 6, 0, 0, 1364, 1365, 7, 7, 0, 0, 1365, 1366, 7, 18, 0, 0, 1366, 316,\n\t\t1, 0, 0, 0, 1367, 1368, 7, 5, 0, 0, 1368, 1369, 7, 16, 0, 0, 1369, 1370,\n\t\t7, 17, 0, 0, 1370, 1371, 7, 10, 0, 0, 1371, 1372, 5, 95, 0, 0, 1372, 1373,\n\t\t7, 8, 0, 0, 1373, 1374, 7, 6, 0, 0, 1374, 1375, 7, 14, 0, 0, 1375, 1376,\n\t\t7, 4, 0, 0, 1376, 318, 1, 0, 0, 0, 1377, 1378, 7, 8, 0, 0, 1378, 1379,\n\t\t7, 10, 0, 0, 1379, 1380, 7, 7, 0, 0, 1380, 1381, 7, 14, 0, 0, 1381, 1382,\n\t\t7, 10, 0, 0, 1382, 1383, 5, 95, 0, 0, 1383, 1384, 7, 3, 0, 0, 1384, 1385,\n\t\t7, 0, 0, 0, 1385, 1386, 7, 7, 0, 0, 1386, 1387, 7, 20, 0, 0, 1387, 320,\n\t\t1, 0, 0, 0, 1388, 1389, 7, 11, 0, 0, 1389, 1390, 7, 0, 0, 0, 1390, 1391,\n\t\t7, 18, 0, 0, 1391, 322, 1, 0, 0, 0, 1392, 1393, 7, 11, 0, 0, 1393, 1394,\n\t\t7, 0, 0, 0, 1394, 1395, 7, 14, 0, 0, 1395, 1396, 7, 4, 0, 0, 1396, 1397,\n\t\t5, 95, 0, 0, 1397, 1398, 7, 23, 0, 0, 1398, 1399, 7, 0, 0, 0, 1399, 1400,\n\t\t7, 11, 0, 0, 1400, 1401, 7, 16, 0, 0, 1401, 1402, 7, 10, 0, 0, 1402, 324,\n\t\t1, 0, 0, 0, 1403, 1404, 7, 11, 0, 0, 1404, 1405, 7, 10, 0, 0, 1405, 1406,\n\t\t7, 0, 0, 0, 1406, 1407, 7, 8, 0, 0, 1407, 326, 1, 0, 0, 0, 1408, 1409,\n\t\t7, 7, 0, 0, 1409, 1410, 7, 4, 0, 0, 1410, 1411, 7, 15, 0, 0, 1411, 1412,\n\t\t5, 95, 0, 0, 1412, 1413, 7, 23, 0, 0, 1413, 1414, 7, 0, 0, 0, 1414, 1415,\n\t\t7, 11, 0, 0, 1415, 1416, 7, 16, 0, 0, 1416, 1417, 7, 10, 0, 0, 1417, 328,\n\t\t1, 0, 0, 0, 1418, 1419, 7, 7, 0, 0, 1419, 1420, 7, 4, 0, 0, 1420, 1421,\n\t\t7, 6, 0, 0, 1421, 1422, 7, 11, 0, 0, 1422, 1423, 7, 10, 0, 0, 1423, 330,\n\t\t1, 0, 0, 0, 1424, 1425, 7, 21, 0, 0, 1425, 1426, 7, 10, 0, 0, 1426, 1427,\n\t\t7, 3, 0, 0, 1427, 1428, 7, 5, 0, 0, 1428, 1429, 7, 10, 0, 0, 1429, 1430,\n\t\t7, 7, 0, 0, 1430, 1431, 7, 4, 0, 0, 1431, 1432, 5, 95, 0, 0, 1432, 1433,\n\t\t7, 3, 0, 0, 1433, 1434, 7, 0, 0, 0, 1434, 1435, 7, 7, 0, 0, 1435, 1436,\n\t\t7, 20, 0, 0, 1436, 332, 1, 0, 0, 0, 1437, 1438, 7, 3, 0, 0, 1438, 1439,\n\t\t7, 0, 0, 0, 1439, 1440, 7, 7, 0, 0, 1440, 1441, 7, 20, 0, 0, 1441, 334,\n\t\t1, 0, 0, 0, 1442, 1443, 7, 3, 0, 0, 1443, 1444, 7, 2, 0, 0, 1444, 1445,\n\t\t7, 19, 0, 0, 1445, 1446, 5, 95, 0, 0, 1446, 1447, 7, 7, 0, 0, 1447, 1448,\n\t\t7, 16, 0, 0, 1448, 1449, 7, 17, 0, 0, 1449, 1450, 7, 1, 0, 0, 1450, 1451,\n\t\t7, 10, 0, 0, 1451, 1452, 7, 3, 0, 0, 1452, 336, 1, 0, 0, 0, 1453, 1454,\n\t\t7, 18, 0, 0, 1454, 1455, 7, 10, 0, 0, 1455, 1456, 7, 7, 0, 0, 1456, 1457,\n\t\t7, 10, 0, 0, 1457, 1458, 7, 3, 0, 0, 1458, 1459, 7, 0, 0, 0, 1459, 1460,\n\t\t7, 4, 0, 0, 1460, 1461, 7, 10, 0, 0, 1461, 1462, 7, 8, 0, 0, 1462, 338,\n\t\t1, 0, 0, 0, 1463, 1464, 7, 0, 0, 0, 1464, 1465, 7, 11, 0, 0, 1465, 1466,\n\t\t7, 19, 0, 0, 1466, 1467, 7, 0, 0, 0, 1467, 1468, 7, 12, 0, 0, 1468, 1469,\n\t\t7, 14, 0, 0, 1469, 340, 1, 0, 0, 0, 1470, 1471, 7, 14, 0, 0, 1471, 1472,\n\t\t7, 4, 0, 0, 1472, 1473, 7, 2, 0, 0, 1473, 1474, 7, 3, 0, 0, 1474, 1475,\n\t\t7, 10, 0, 0, 1475, 1476, 7, 8, 0, 0, 1476, 342, 1, 0, 0, 0, 1477, 1478,\n\t\t7, 4, 0, 0, 1478, 1479, 7, 3, 0, 0, 1479, 1480, 7, 16, 0, 0, 1480, 1481,\n\t\t7, 10, 0, 0, 1481, 344, 1, 0, 0, 0, 1482, 1483, 7, 9, 0, 0, 1483, 1484,\n\t\t7, 0, 0, 0, 1484, 1485, 7, 11, 0, 0, 1485, 1486, 7, 14, 0, 0, 1486, 1487,\n\t\t7, 10, 0, 0, 1487, 346, 1, 0, 0, 0, 1488, 1489, 7, 19, 0, 0, 1489, 1490,\n\t\t7, 6, 0, 0, 1490, 1491, 7, 7, 0, 0, 1491, 1492, 7, 8, 0, 0, 1492, 1493,\n\t\t7, 2, 0, 0, 1493, 1494, 7, 19, 0, 0, 1494, 348, 1, 0, 0, 0, 1495, 1496,\n\t\t7, 7, 0, 0, 1496, 1497, 7, 16, 0, 0, 1497, 1498, 7, 11, 0, 0, 1498, 1499,\n\t\t7, 11, 0, 0, 1499, 1500, 7, 14, 0, 0, 1500, 350, 1, 0, 0, 0, 1501, 1502,\n\t\t7, 9, 0, 0, 1502, 1503, 7, 6, 0, 0, 1503, 1504, 7, 3, 0, 0, 1504, 1505,\n\t\t7, 14, 0, 0, 1505, 1506, 7, 4, 0, 0, 1506, 352, 1, 0, 0, 0, 1507, 1508,\n\t\t7, 11, 0, 0, 1508, 1509, 7, 0, 0, 0, 1509, 1510, 7, 14, 0, 0, 1510, 1511,\n\t\t7, 4, 0, 0, 1511, 354, 1, 0, 0, 0, 1512, 1513, 7, 9, 0, 0, 1513, 1514,\n\t\t7, 6, 0, 0, 1514, 1515, 7, 11, 0, 0, 1515, 1516, 7, 4, 0, 0, 1516, 1517,\n\t\t7, 10, 0, 0, 1517, 1518, 7, 3, 0, 0, 1518, 356, 1, 0, 0, 0, 1519, 1520,\n\t\t7, 18, 0, 0, 1520, 1521, 7, 3, 0, 0, 1521, 1522, 7, 2, 0, 0, 1522, 1523,\n\t\t7, 16, 0, 0, 1523, 1524, 7, 21, 0, 0, 1524, 1525, 7, 14, 0, 0, 1525, 358,\n\t\t1, 0, 0, 0, 1526, 1527, 7, 10, 0, 0, 1527, 1528, 7, 22, 0, 0, 1528, 1529,\n\t\t7, 5, 0, 0, 1529, 1530, 7, 11, 0, 0, 1530, 1531, 7, 16, 0, 0, 1531, 1532,\n\t\t7, 8, 0, 0, 1532, 1533, 7, 10, 0, 0, 1533, 360, 1, 0, 0, 0, 1534, 1535,\n\t\t7, 4, 0, 0, 1535, 1536, 7, 6, 0, 0, 1536, 1537, 7, 10, 0, 0, 1537, 1538,\n\t\t7, 14, 0, 0, 1538, 362, 1, 0, 0, 0, 1539, 1540, 7, 2, 0, 0, 1540, 1541,\n\t\t7, 4, 0, 0, 1541, 1542, 7, 15, 0, 0, 1542, 1543, 7, 10, 0, 0, 1543, 1544,\n\t\t7, 3, 0, 0, 1544, 1545, 7, 14, 0, 0, 1545, 364, 1, 0, 0, 0, 1546, 1547,\n\t\t7, 8, 0, 0, 1547, 1548, 7, 2, 0, 0, 1548, 366, 1, 0, 0, 0, 1549, 1550,\n\t\t7, 7, 0, 0, 1550, 1551, 7, 2, 0, 0, 1551, 1552, 7, 4, 0, 0, 1552, 1553,\n\t\t7, 15, 0, 0, 1553, 1554, 7, 6, 0, 0, 1554, 1555, 7, 7, 0, 0, 1555, 1556,\n\t\t7, 18, 0, 0, 1556, 368, 1, 0, 0, 0, 1557, 1563, 5, 34, 0, 0, 1558, 1562,\n\t\t8, 26, 0, 0, 1559, 1560, 5, 34, 0, 0, 1560, 1562, 5, 34, 0, 0, 1561, 1558,\n\t\t1, 0, 0, 0, 1561, 1559, 1, 0, 0, 0, 1562, 1565, 1, 0, 0, 0, 1563, 1561,\n\t\t1, 0, 0, 0, 1563, 1564, 1, 0, 0, 0, 1564, 1566, 1, 0, 0, 0, 1565, 1563,\n\t\t1, 0, 0, 0, 1566, 1593, 5, 34, 0, 0, 1567, 1573, 5, 96, 0, 0, 1568, 1572,\n\t\t8, 27, 0, 0, 1569, 1570, 5, 96, 0, 0, 1570, 1572, 5, 96, 0, 0, 1571, 1568,\n\t\t1, 0, 0, 0, 1571, 1569, 1, 0, 0, 0, 1572, 1575, 1, 0, 0, 0, 1573, 1571,\n\t\t1, 0, 0, 0, 1573, 1574, 1, 0, 0, 0, 1574, 1576, 1, 0, 0, 0, 1575, 1573,\n\t\t1, 0, 0, 0, 1576, 1593, 5, 96, 0, 0, 1577, 1581, 5, 91, 0, 0, 1578, 1580,\n\t\t8, 28, 0, 0, 1579, 1578, 1, 0, 0, 0, 1580, 1583, 1, 0, 0, 0, 1581, 1579,\n\t\t1, 0, 0, 0, 1581, 1582, 1, 0, 0, 0, 1582, 1584, 1, 0, 0, 0, 1583, 1581,\n\t\t1, 0, 0, 0, 1584, 1593, 5, 93, 0, 0, 1585, 1589, 7, 29, 0, 0, 1586, 1588,\n\t\t7, 30, 0, 0, 1587, 1586, 1, 0, 0, 0, 1588, 1591, 1, 0, 0, 0, 1589, 1587,\n\t\t1, 0, 0, 0, 1589, 1590, 1, 0, 0, 0, 1590, 1593, 1, 0, 0, 0, 1591, 1589,\n\t\t1, 0, 0, 0, 1592, 1557, 1, 0, 0, 0, 1592, 1567, 1, 0, 0, 0, 1592, 1577,\n\t\t1, 0, 0, 0, 1592, 1585, 1, 0, 0, 0, 1593, 370, 1, 0, 0, 0, 1594, 1596,\n\t\t3, 389, 194, 0, 1595, 1594, 1, 0, 0, 0, 1596, 1597, 1, 0, 0, 0, 1597, 1595,\n\t\t1, 0, 0, 0, 1597, 1598, 1, 0, 0, 0, 1598, 1606, 1, 0, 0, 0, 1599, 1603,\n\t\t5, 46, 0, 0, 1600, 1602, 3, 389, 194, 0, 1601, 1600, 1, 0, 0, 0, 1602,\n\t\t1605, 1, 0, 0, 0, 1603, 1601, 1, 0, 0, 0, 1603, 1604, 1, 0, 0, 0, 1604,\n\t\t1607, 1, 0, 0, 0, 1605, 1603, 1, 0, 0, 0, 1606, 1599, 1, 0, 0, 0, 1606,\n\t\t1607, 1, 0, 0, 0, 1607, 1615, 1, 0, 0, 0, 1608, 1610, 5, 46, 0, 0, 1609,\n\t\t1611, 3, 389, 194, 0, 1610, 1609, 1, 0, 0, 0, 1611, 1612, 1, 0, 0, 0, 1612,\n\t\t1610, 1, 0, 0, 0, 1612, 1613, 1, 0, 0, 0, 1613, 1615, 1, 0, 0, 0, 1614,\n\t\t1595, 1, 0, 0, 0, 1614, 1608, 1, 0, 0, 0, 1615, 1625, 1, 0, 0, 0, 1616,\n\t\t1618, 7, 10, 0, 0, 1617, 1619, 7, 31, 0, 0, 1618, 1617, 1, 0, 0, 0, 1618,\n\t\t1619, 1, 0, 0, 0, 1619, 1621, 1, 0, 0, 0, 1620, 1622, 3, 389, 194, 0, 1621,\n\t\t1620, 1, 0, 0, 0, 1622, 1623, 1, 0, 0, 0, 1623, 1621, 1, 0, 0, 0, 1623,\n\t\t1624, 1, 0, 0, 0, 1624, 1626, 1, 0, 0, 0, 1625, 1616, 1, 0, 0, 0, 1625,\n\t\t1626, 1, 0, 0, 0, 1626, 1636, 1, 0, 0, 0, 1627, 1628, 5, 48, 0, 0, 1628,\n\t\t1629, 7, 22, 0, 0, 1629, 1631, 1, 0, 0, 0, 1630, 1632, 3, 387, 193, 0,\n\t\t1631, 1630, 1, 0, 0, 0, 1632, 1633, 1, 0, 0, 0, 1633, 1631, 1, 0, 0, 0,\n\t\t1633, 1634, 1, 0, 0, 0, 1634, 1636, 1, 0, 0, 0, 1635, 1614, 1, 0, 0, 0,\n\t\t1635, 1627, 1, 0, 0, 0, 1636, 372, 1, 0, 0, 0, 1637, 1641, 5, 63, 0, 0,\n\t\t1638, 1640, 3, 389, 194, 0, 1639, 1638, 1, 0, 0, 0, 1640, 1643, 1, 0, 0,\n\t\t0, 1641, 1639, 1, 0, 0, 0, 1641, 1642, 1, 0, 0, 0, 1642, 1647, 1, 0, 0,\n\t\t0, 1643, 1641, 1, 0, 0, 0, 1644, 1645, 7, 32, 0, 0, 1645, 1647, 3, 369,\n\t\t184, 0, 1646, 1637, 1, 0, 0, 0, 1646, 1644, 1, 0, 0, 0, 1647, 374, 1, 0,\n\t\t0, 0, 1648, 1654, 5, 39, 0, 0, 1649, 1653, 8, 33, 0, 0, 1650, 1651, 5,\n\t\t39, 0, 0, 1651, 1653, 5, 39, 0, 0, 1652, 1649, 1, 0, 0, 0, 1652, 1650,\n\t\t1, 0, 0, 0, 1653, 1656, 1, 0, 0, 0, 1654, 1652, 1, 0, 0, 0, 1654, 1655,\n\t\t1, 0, 0, 0, 1655, 1657, 1, 0, 0, 0, 1656, 1654, 1, 0, 0, 0, 1657, 1658,\n\t\t5, 39, 0, 0, 1658, 376, 1, 0, 0, 0, 1659, 1660, 7, 22, 0, 0, 1660, 1661,\n\t\t3, 375, 187, 0, 1661, 378, 1, 0, 0, 0, 1662, 1663, 5, 45, 0, 0, 1663, 1664,\n\t\t5, 45, 0, 0, 1664, 1668, 1, 0, 0, 0, 1665, 1667, 8, 34, 0, 0, 1666, 1665,\n\t\t1, 0, 0, 0, 1667, 1670, 1, 0, 0, 0, 1668, 1666, 1, 0, 0, 0, 1668, 1669,\n\t\t1, 0, 0, 0, 1669, 1676, 1, 0, 0, 0, 1670, 1668, 1, 0, 0, 0, 1671, 1673,\n\t\t5, 13, 0, 0, 1672, 1671, 1, 0, 0, 0, 1672, 1673, 1, 0, 0, 0, 1673, 1674,\n\t\t1, 0, 0, 0, 1674, 1677, 5, 10, 0, 0, 1675, 1677, 5, 0, 0, 1, 1676, 1672,\n\t\t1, 0, 0, 0, 1676, 1675, 1, 0, 0, 0, 1677, 1678, 1, 0, 0, 0, 1678, 1679,\n\t\t6, 189, 0, 0, 1679, 380, 1, 0, 0, 0, 1680, 1681, 5, 47, 0, 0, 1681, 1682,\n\t\t5, 42, 0, 0, 1682, 1686, 1, 0, 0, 0, 1683, 1685, 9, 0, 0, 0, 1684, 1683,\n\t\t1, 0, 0, 0, 1685, 1688, 1, 0, 0, 0, 1686, 1687, 1, 0, 0, 0, 1686, 1684,\n\t\t1, 0, 0, 0, 1687, 1689, 1, 0, 0, 0, 1688, 1686, 1, 0, 0, 0, 1689, 1690,\n\t\t5, 42, 0, 0, 1690, 1691, 5, 47, 0, 0, 1691, 1692, 1, 0, 0, 0, 1692, 1693,\n\t\t6, 190, 0, 0, 1693, 382, 1, 0, 0, 0, 1694, 1695, 7, 35, 0, 0, 1695, 1696,\n\t\t1, 0, 0, 0, 1696, 1697, 6, 191, 0, 0, 1697, 384, 1, 0, 0, 0, 1698, 1699,\n\t\t9, 0, 0, 0, 1699, 386, 1, 0, 0, 0, 1700, 1701, 7, 36, 0, 0, 1701, 388,\n\t\t1, 0, 0, 0, 1702, 1703, 7, 37, 0, 0, 1703, 390, 1, 0, 0, 0, 26, 0, 1561,\n\t\t1563, 1571, 1573, 1581, 1589, 1592, 1597, 1603, 1606, 1612, 1614, 1618,\n\t\t1623, 1625, 1633, 1635, 1641, 1646, 1652, 1654, 1668, 1672, 1676, 1686,\n\t\t1, 0, 1, 0,\n\t}\n\tdeserializer := antlr.NewATNDeserializer(nil)\n\tstaticData.atn = deserializer.Deserialize(staticData.serializedATN)\n\tatn := staticData.atn\n\tstaticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState))\n\tdecisionToDFA := staticData.decisionToDFA\n\tfor index, state := range atn.DecisionToState {\n\t\tdecisionToDFA[index] = antlr.NewDFA(state, index)\n\t}\n}\n\n// LexerInit initializes any static state used to implement Lexer. By default the\n// static state used to implement the lexer is lazily initialized during the first call to\n// NewLexer(). You can call this function if you wish to initialize the static state ahead\n// of time.\nfunc LexerInit() {\n\tstaticData := &LexerLexerStaticData\n\tstaticData.once.Do(lexerLexerInit)\n}\n\n// NewLexer produces a new lexer instance for the optional input antlr.CharStream.\nfunc NewLexer(input antlr.CharStream) *Lexer {\n\tLexerInit()\n\tl := new(Lexer)\n\tl.BaseLexer = antlr.NewBaseLexer(input)\n\tstaticData := &LexerLexerStaticData\n\tl.Interpreter = antlr.NewLexerATNSimulator(l, staticData.atn, staticData.decisionToDFA, staticData.PredictionContextCache)\n\tl.channelNames = staticData.ChannelNames\n\tl.modeNames = staticData.ModeNames\n\tl.RuleNames = staticData.RuleNames\n\tl.LiteralNames = staticData.LiteralNames\n\tl.SymbolicNames = staticData.SymbolicNames\n\tl.GrammarFileName = \"Lexer.g4\"\n\t// TODO: l.EOF = antlr.TokenEOF\n\n\treturn l\n}\n\n// Lexer tokens.\nconst (\n\tLexerSCOL                = 1\n\tLexerDOT                 = 2\n\tLexerOPEN_PAR            = 3\n\tLexerCLOSE_PAR           = 4\n\tLexerCOMMA               = 5\n\tLexerASSIGN              = 6\n\tLexerSTAR                = 7\n\tLexerPLUS                = 8\n\tLexerMINUS               = 9\n\tLexerTILDE               = 10\n\tLexerPIPE2               = 11\n\tLexerDIV                 = 12\n\tLexerMOD                 = 13\n\tLexerLT2                 = 14\n\tLexerGT2                 = 15\n\tLexerAMP                 = 16\n\tLexerPIPE                = 17\n\tLexerLT                  = 18\n\tLexerLT_EQ               = 19\n\tLexerGT                  = 20\n\tLexerGT_EQ               = 21\n\tLexerEQ                  = 22\n\tLexerNOT_EQ1             = 23\n\tLexerNOT_EQ2             = 24\n\tLexerABORT_              = 25\n\tLexerACTION_             = 26\n\tLexerADD_                = 27\n\tLexerAFTER_              = 28\n\tLexerALL_                = 29\n\tLexerALTER_              = 30\n\tLexerANALYZE_            = 31\n\tLexerAND_                = 32\n\tLexerAS_                 = 33\n\tLexerASC_                = 34\n\tLexerATTACH_             = 35\n\tLexerAUTOINCREMENT_      = 36\n\tLexerBEFORE_             = 37\n\tLexerBEGIN_              = 38\n\tLexerBETWEEN_            = 39\n\tLexerBY_                 = 40\n\tLexerCASCADE_            = 41\n\tLexerCASE_               = 42\n\tLexerCAST_               = 43\n\tLexerCHECK_              = 44\n\tLexerCOLLATE_            = 45\n\tLexerCOLUMN_             = 46\n\tLexerCOMMIT_             = 47\n\tLexerCONFLICT_           = 48\n\tLexerCONSTRAINT_         = 49\n\tLexerCREATE_             = 50\n\tLexerCROSS_              = 51\n\tLexerCURRENT_DATE_       = 52\n\tLexerCURRENT_TIME_       = 53\n\tLexerCURRENT_TIMESTAMP_  = 54\n\tLexerDATABASE_           = 55\n\tLexerDEFAULT_            = 56\n\tLexerDEFERRABLE_         = 57\n\tLexerDEFERRED_           = 58\n\tLexerDELETE_             = 59\n\tLexerDESC_               = 60\n\tLexerDETACH_             = 61\n\tLexerDISTINCT_           = 62\n\tLexerDROP_               = 63\n\tLexerEACH_               = 64\n\tLexerELSE_               = 65\n\tLexerEND_                = 66\n\tLexerESCAPE_             = 67\n\tLexerEXCEPT_             = 68\n\tLexerEXCLUSIVE_          = 69\n\tLexerEXISTS_             = 70\n\tLexerEXPLAIN_            = 71\n\tLexerFAIL_               = 72\n\tLexerFOR_                = 73\n\tLexerFOREIGN_            = 74\n\tLexerFROM_               = 75\n\tLexerFULL_               = 76\n\tLexerGLOB_               = 77\n\tLexerGROUP_              = 78\n\tLexerHAVING_             = 79\n\tLexerIF_                 = 80\n\tLexerIGNORE_             = 81\n\tLexerIMMEDIATE_          = 82\n\tLexerIN_                 = 83\n\tLexerINDEX_              = 84\n\tLexerINDEXED_            = 85\n\tLexerINITIALLY_          = 86\n\tLexerINNER_              = 87\n\tLexerINSERT_             = 88\n\tLexerINSTEAD_            = 89\n\tLexerINTERSECT_          = 90\n\tLexerINTO_               = 91\n\tLexerIS_                 = 92\n\tLexerISNULL_             = 93\n\tLexerJOIN_               = 94\n\tLexerKEY_                = 95\n\tLexerLEFT_               = 96\n\tLexerLIKE_               = 97\n\tLexerLIMIT_              = 98\n\tLexerMATCH_              = 99\n\tLexerNATURAL_            = 100\n\tLexerNO_                 = 101\n\tLexerNOT_                = 102\n\tLexerNOTNULL_            = 103\n\tLexerNULL_               = 104\n\tLexerOF_                 = 105\n\tLexerOFFSET_             = 106\n\tLexerON_                 = 107\n\tLexerOR_                 = 108\n\tLexerORDER_              = 109\n\tLexerOUTER_              = 110\n\tLexerPLAN_               = 111\n\tLexerPRAGMA_             = 112\n\tLexerPRIMARY_            = 113\n\tLexerQUERY_              = 114\n\tLexerRAISE_              = 115\n\tLexerRECURSIVE_          = 116\n\tLexerREFERENCES_         = 117\n\tLexerREGEXP_             = 118\n\tLexerREINDEX_            = 119\n\tLexerRELEASE_            = 120\n\tLexerRENAME_             = 121\n\tLexerREPLACE_            = 122\n\tLexerRESTRICT_           = 123\n\tLexerRETURNING_          = 124\n\tLexerRIGHT_              = 125\n\tLexerROLLBACK_           = 126\n\tLexerROW_                = 127\n\tLexerROWS_               = 128\n\tLexerSAVEPOINT_          = 129\n\tLexerSELECT_             = 130\n\tLexerSET_                = 131\n\tLexerTABLE_              = 132\n\tLexerTEMP_               = 133\n\tLexerTEMPORARY_          = 134\n\tLexerTHEN_               = 135\n\tLexerTO_                 = 136\n\tLexerTRANSACTION_        = 137\n\tLexerTRIGGER_            = 138\n\tLexerUNION_              = 139\n\tLexerUNIQUE_             = 140\n\tLexerUPDATE_             = 141\n\tLexerUSING_              = 142\n\tLexerVACUUM_             = 143\n\tLexerVALUES_             = 144\n\tLexerVIEW_               = 145\n\tLexerVIRTUAL_            = 146\n\tLexerWHEN_               = 147\n\tLexerWHERE_              = 148\n\tLexerWITH_               = 149\n\tLexerWITHOUT_            = 150\n\tLexerFIRST_VALUE_        = 151\n\tLexerOVER_               = 152\n\tLexerPARTITION_          = 153\n\tLexerRANGE_              = 154\n\tLexerPRECEDING_          = 155\n\tLexerUNBOUNDED_          = 156\n\tLexerCURRENT_            = 157\n\tLexerFOLLOWING_          = 158\n\tLexerCUME_DIST_          = 159\n\tLexerDENSE_RANK_         = 160\n\tLexerLAG_                = 161\n\tLexerLAST_VALUE_         = 162\n\tLexerLEAD_               = 163\n\tLexerNTH_VALUE_          = 164\n\tLexerNTILE_              = 165\n\tLexerPERCENT_RANK_       = 166\n\tLexerRANK_               = 167\n\tLexerROW_NUMBER_         = 168\n\tLexerGENERATED_          = 169\n\tLexerALWAYS_             = 170\n\tLexerSTORED_             = 171\n\tLexerTRUE_               = 172\n\tLexerFALSE_              = 173\n\tLexerWINDOW_             = 174\n\tLexerNULLS_              = 175\n\tLexerFIRST_              = 176\n\tLexerLAST_               = 177\n\tLexerFILTER_             = 178\n\tLexerGROUPS_             = 179\n\tLexerEXCLUDE_            = 180\n\tLexerTIES_               = 181\n\tLexerOTHERS_             = 182\n\tLexerDO_                 = 183\n\tLexerNOTHING_            = 184\n\tLexerIDENTIFIER          = 185\n\tLexerNUMERIC_LITERAL     = 186\n\tLexerBIND_PARAMETER      = 187\n\tLexerSTRING_LITERAL      = 188\n\tLexerBLOB_LITERAL        = 189\n\tLexerSINGLE_LINE_COMMENT = 190\n\tLexerMULTILINE_COMMENT   = 191\n\tLexerSPACES              = 192\n\tLexerUNEXPECTED_CHAR     = 193\n)\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqliteparse/parser.go",
    "content": "// Code generated from Parser.g4 by ANTLR 4.13.1. DO NOT EDIT.\n\npackage sqliteparse // Parser\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"sync\"\n\n\t\"github.com/antlr4-go/antlr/v4\"\n)\n\n// Suppress unused import errors\nvar _ = fmt.Printf\nvar _ = strconv.Itoa\nvar _ = sync.Once{}\n\ntype Parser struct {\n\t*antlr.BaseParser\n}\n\nvar ParserParserStaticData struct {\n\tonce                   sync.Once\n\tserializedATN          []int32\n\tLiteralNames           []string\n\tSymbolicNames          []string\n\tRuleNames              []string\n\tPredictionContextCache *antlr.PredictionContextCache\n\tatn                    *antlr.ATN\n\tdecisionToDFA          []*antlr.DFA\n}\n\nfunc parserParserInit() {\n\tstaticData := &ParserParserStaticData\n\tstaticData.LiteralNames = []string{\n\t\t\"\", \"';'\", \"'.'\", \"'('\", \"')'\", \"','\", \"'='\", \"'*'\", \"'+'\", \"'-'\", \"'~'\",\n\t\t\"'||'\", \"'/'\", \"'%'\", \"'<<'\", \"'>>'\", \"'&'\", \"'|'\", \"'<'\", \"'<='\", \"'>'\",\n\t\t\"'>='\", \"'=='\", \"'!='\", \"'<>'\", \"'ABORT'\", \"'ACTION'\", \"'ADD'\", \"'AFTER'\",\n\t\t\"'ALL'\", \"'ALTER'\", \"'ANALYZE'\", \"'AND'\", \"'AS'\", \"'ASC'\", \"'ATTACH'\",\n\t\t\"'AUTOINCREMENT'\", \"'BEFORE'\", \"'BEGIN'\", \"'BETWEEN'\", \"'BY'\", \"'CASCADE'\",\n\t\t\"'CASE'\", \"'CAST'\", \"'CHECK'\", \"'COLLATE'\", \"'COLUMN'\", \"'COMMIT'\",\n\t\t\"'CONFLICT'\", \"'CONSTRAINT'\", \"'CREATE'\", \"'CROSS'\", \"'CURRENT_DATE'\",\n\t\t\"'CURRENT_TIME'\", \"'CURRENT_TIMESTAMP'\", \"'DATABASE'\", \"'DEFAULT'\",\n\t\t\"'DEFERRABLE'\", \"'DEFERRED'\", \"'DELETE'\", \"'DESC'\", \"'DETACH'\", \"'DISTINCT'\",\n\t\t\"'DROP'\", \"'EACH'\", \"'ELSE'\", \"'END'\", \"'ESCAPE'\", \"'EXCEPT'\", \"'EXCLUSIVE'\",\n\t\t\"'EXISTS'\", \"'EXPLAIN'\", \"'FAIL'\", \"'FOR'\", \"'FOREIGN'\", \"'FROM'\", \"'FULL'\",\n\t\t\"'GLOB'\", \"'GROUP'\", \"'HAVING'\", \"'IF'\", \"'IGNORE'\", \"'IMMEDIATE'\",\n\t\t\"'IN'\", \"'INDEX'\", \"'INDEXED'\", \"'INITIALLY'\", \"'INNER'\", \"'INSERT'\",\n\t\t\"'INSTEAD'\", \"'INTERSECT'\", \"'INTO'\", \"'IS'\", \"'ISNULL'\", \"'JOIN'\",\n\t\t\"'KEY'\", \"'LEFT'\", \"'LIKE'\", \"'LIMIT'\", \"'MATCH'\", \"'NATURAL'\", \"'NO'\",\n\t\t\"'NOT'\", \"'NOTNULL'\", \"'NULL'\", \"'OF'\", \"'OFFSET'\", \"'ON'\", \"'OR'\",\n\t\t\"'ORDER'\", \"'OUTER'\", \"'PLAN'\", \"'PRAGMA'\", \"'PRIMARY'\", \"'QUERY'\",\n\t\t\"'RAISE'\", \"'RECURSIVE'\", \"'REFERENCES'\", \"'REGEXP'\", \"'REINDEX'\", \"'RELEASE'\",\n\t\t\"'RENAME'\", \"'REPLACE'\", \"'RESTRICT'\", \"'RETURNING'\", \"'RIGHT'\", \"'ROLLBACK'\",\n\t\t\"'ROW'\", \"'ROWS'\", \"'SAVEPOINT'\", \"'SELECT'\", \"'SET'\", \"'TABLE'\", \"'TEMP'\",\n\t\t\"'TEMPORARY'\", \"'THEN'\", \"'TO'\", \"'TRANSACTION'\", \"'TRIGGER'\", \"'UNION'\",\n\t\t\"'UNIQUE'\", \"'UPDATE'\", \"'USING'\", \"'VACUUM'\", \"'VALUES'\", \"'VIEW'\",\n\t\t\"'VIRTUAL'\", \"'WHEN'\", \"'WHERE'\", \"'WITH'\", \"'WITHOUT'\", \"'FIRST_VALUE'\",\n\t\t\"'OVER'\", \"'PARTITION'\", \"'RANGE'\", \"'PRECEDING'\", \"'UNBOUNDED'\", \"'CURRENT'\",\n\t\t\"'FOLLOWING'\", \"'CUME_DIST'\", \"'DENSE_RANK'\", \"'LAG'\", \"'LAST_VALUE'\",\n\t\t\"'LEAD'\", \"'NTH_VALUE'\", \"'NTILE'\", \"'PERCENT_RANK'\", \"'RANK'\", \"'ROW_NUMBER'\",\n\t\t\"'GENERATED'\", \"'ALWAYS'\", \"'STORED'\", \"'TRUE'\", \"'FALSE'\", \"'WINDOW'\",\n\t\t\"'NULLS'\", \"'FIRST'\", \"'LAST'\", \"'FILTER'\", \"'GROUPS'\", \"'EXCLUDE'\",\n\t\t\"'TIES'\", \"'OTHERS'\", \"'DO'\", \"'NOTHING'\",\n\t}\n\tstaticData.SymbolicNames = []string{\n\t\t\"\", \"SCOL\", \"DOT\", \"OPEN_PAR\", \"CLOSE_PAR\", \"COMMA\", \"ASSIGN\", \"STAR\",\n\t\t\"PLUS\", \"MINUS\", \"TILDE\", \"PIPE2\", \"DIV\", \"MOD\", \"LT2\", \"GT2\", \"AMP\",\n\t\t\"PIPE\", \"LT\", \"LT_EQ\", \"GT\", \"GT_EQ\", \"EQ\", \"NOT_EQ1\", \"NOT_EQ2\", \"ABORT_\",\n\t\t\"ACTION_\", \"ADD_\", \"AFTER_\", \"ALL_\", \"ALTER_\", \"ANALYZE_\", \"AND_\", \"AS_\",\n\t\t\"ASC_\", \"ATTACH_\", \"AUTOINCREMENT_\", \"BEFORE_\", \"BEGIN_\", \"BETWEEN_\",\n\t\t\"BY_\", \"CASCADE_\", \"CASE_\", \"CAST_\", \"CHECK_\", \"COLLATE_\", \"COLUMN_\",\n\t\t\"COMMIT_\", \"CONFLICT_\", \"CONSTRAINT_\", \"CREATE_\", \"CROSS_\", \"CURRENT_DATE_\",\n\t\t\"CURRENT_TIME_\", \"CURRENT_TIMESTAMP_\", \"DATABASE_\", \"DEFAULT_\", \"DEFERRABLE_\",\n\t\t\"DEFERRED_\", \"DELETE_\", \"DESC_\", \"DETACH_\", \"DISTINCT_\", \"DROP_\", \"EACH_\",\n\t\t\"ELSE_\", \"END_\", \"ESCAPE_\", \"EXCEPT_\", \"EXCLUSIVE_\", \"EXISTS_\", \"EXPLAIN_\",\n\t\t\"FAIL_\", \"FOR_\", \"FOREIGN_\", \"FROM_\", \"FULL_\", \"GLOB_\", \"GROUP_\", \"HAVING_\",\n\t\t\"IF_\", \"IGNORE_\", \"IMMEDIATE_\", \"IN_\", \"INDEX_\", \"INDEXED_\", \"INITIALLY_\",\n\t\t\"INNER_\", \"INSERT_\", \"INSTEAD_\", \"INTERSECT_\", \"INTO_\", \"IS_\", \"ISNULL_\",\n\t\t\"JOIN_\", \"KEY_\", \"LEFT_\", \"LIKE_\", \"LIMIT_\", \"MATCH_\", \"NATURAL_\", \"NO_\",\n\t\t\"NOT_\", \"NOTNULL_\", \"NULL_\", \"OF_\", \"OFFSET_\", \"ON_\", \"OR_\", \"ORDER_\",\n\t\t\"OUTER_\", \"PLAN_\", \"PRAGMA_\", \"PRIMARY_\", \"QUERY_\", \"RAISE_\", \"RECURSIVE_\",\n\t\t\"REFERENCES_\", \"REGEXP_\", \"REINDEX_\", \"RELEASE_\", \"RENAME_\", \"REPLACE_\",\n\t\t\"RESTRICT_\", \"RETURNING_\", \"RIGHT_\", \"ROLLBACK_\", \"ROW_\", \"ROWS_\", \"SAVEPOINT_\",\n\t\t\"SELECT_\", \"SET_\", \"TABLE_\", \"TEMP_\", \"TEMPORARY_\", \"THEN_\", \"TO_\",\n\t\t\"TRANSACTION_\", \"TRIGGER_\", \"UNION_\", \"UNIQUE_\", \"UPDATE_\", \"USING_\",\n\t\t\"VACUUM_\", \"VALUES_\", \"VIEW_\", \"VIRTUAL_\", \"WHEN_\", \"WHERE_\", \"WITH_\",\n\t\t\"WITHOUT_\", \"FIRST_VALUE_\", \"OVER_\", \"PARTITION_\", \"RANGE_\", \"PRECEDING_\",\n\t\t\"UNBOUNDED_\", \"CURRENT_\", \"FOLLOWING_\", \"CUME_DIST_\", \"DENSE_RANK_\",\n\t\t\"LAG_\", \"LAST_VALUE_\", \"LEAD_\", \"NTH_VALUE_\", \"NTILE_\", \"PERCENT_RANK_\",\n\t\t\"RANK_\", \"ROW_NUMBER_\", \"GENERATED_\", \"ALWAYS_\", \"STORED_\", \"TRUE_\",\n\t\t\"FALSE_\", \"WINDOW_\", \"NULLS_\", \"FIRST_\", \"LAST_\", \"FILTER_\", \"GROUPS_\",\n\t\t\"EXCLUDE_\", \"TIES_\", \"OTHERS_\", \"DO_\", \"NOTHING_\", \"IDENTIFIER\", \"NUMERIC_LITERAL\",\n\t\t\"BIND_PARAMETER\", \"STRING_LITERAL\", \"BLOB_LITERAL\", \"SINGLE_LINE_COMMENT\",\n\t\t\"MULTILINE_COMMENT\", \"SPACES\", \"UNEXPECTED_CHAR\",\n\t}\n\tstaticData.RuleNames = []string{\n\t\t\"parse\", \"sql_stmt_list\", \"sql_stmt\", \"alter_table_stmt\", \"analyze_stmt\",\n\t\t\"attach_stmt\", \"begin_stmt\", \"commit_stmt\", \"rollback_stmt\", \"savepoint_stmt\",\n\t\t\"release_stmt\", \"create_index_stmt\", \"indexed_column\", \"create_table_stmt\",\n\t\t\"column_def\", \"type_name\", \"column_constraint\", \"signed_number\", \"table_constraint\",\n\t\t\"foreign_key_clause\", \"conflict_clause\", \"create_trigger_stmt\", \"create_view_stmt\",\n\t\t\"create_virtual_table_stmt\", \"with_clause\", \"cte_table_name\", \"recursive_cte\",\n\t\t\"common_table_expression\", \"delete_stmt\", \"delete_stmt_limited\", \"detach_stmt\",\n\t\t\"drop_stmt\", \"expr\", \"raise_function\", \"literal_value\", \"insert_stmt\",\n\t\t\"returning_clause\", \"upsert_clause\", \"pragma_stmt\", \"pragma_value\",\n\t\t\"reindex_stmt\", \"select_stmt\", \"join_clause\", \"select_core\", \"factored_select_stmt\",\n\t\t\"simple_select_stmt\", \"compound_select_stmt\", \"table_or_subquery\", \"result_column\",\n\t\t\"join_operator\", \"join_constraint\", \"compound_operator\", \"update_stmt\",\n\t\t\"assignment_list\", \"assignment\", \"column_name_list\", \"update_stmt_limited\",\n\t\t\"qualified_table_name\", \"vacuum_stmt\", \"filter_clause\", \"window_defn\",\n\t\t\"over_clause\", \"frame_spec\", \"frame_clause\", \"simple_function_invocation\",\n\t\t\"aggregate_function_invocation\", \"window_function_invocation\", \"common_table_stmt\",\n\t\t\"order_by_stmt\", \"limit_stmt\", \"ordering_term\", \"asc_desc\", \"frame_left\",\n\t\t\"frame_right\", \"frame_single\", \"window_function\", \"offset\", \"default_value\",\n\t\t\"partition_by\", \"order_by_expr\", \"order_by_expr_asc_desc\", \"expr_asc_desc\",\n\t\t\"initial_select\", \"recursive_select\", \"unary_operator\", \"error_message\",\n\t\t\"module_argument\", \"column_alias\", \"keyword\", \"name\", \"function_name\",\n\t\t\"schema_name\", \"table_name\", \"table_or_index_name\", \"column_name\", \"collation_name\",\n\t\t\"foreign_table\", \"index_name\", \"trigger_name\", \"view_name\", \"module_name\",\n\t\t\"pragma_name\", \"savepoint_name\", \"table_alias\", \"transaction_name\",\n\t\t\"window_name\", \"alias\", \"filename\", \"base_window_name\", \"simple_func\",\n\t\t\"aggregate_func\", \"table_function_name\", \"any_name\",\n\t}\n\tstaticData.PredictionContextCache = antlr.NewPredictionContextCache()\n\tstaticData.serializedATN = []int32{\n\t\t4, 1, 193, 2083, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4,\n\t\t7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10,\n\t\t7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7,\n\t\t15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20,\n\t\t2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2,\n\t\t26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31,\n\t\t7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7,\n\t\t36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41,\n\t\t2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2,\n\t\t47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52,\n\t\t7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7,\n\t\t57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62,\n\t\t2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2,\n\t\t68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73,\n\t\t7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7,\n\t\t78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83,\n\t\t2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2,\n\t\t89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94,\n\t\t7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7,\n\t\t99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2,\n\t\t104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7,\n\t\t108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 1,\n\t\t0, 5, 0, 228, 8, 0, 10, 0, 12, 0, 231, 9, 0, 1, 0, 1, 0, 1, 1, 5, 1, 236,\n\t\t8, 1, 10, 1, 12, 1, 239, 9, 1, 1, 1, 1, 1, 4, 1, 243, 8, 1, 11, 1, 12,\n\t\t1, 244, 1, 1, 5, 1, 248, 8, 1, 10, 1, 12, 1, 251, 9, 1, 1, 1, 5, 1, 254,\n\t\t8, 1, 10, 1, 12, 1, 257, 9, 1, 1, 2, 1, 2, 1, 2, 3, 2, 262, 8, 2, 3, 2,\n\t\t264, 8, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,\n\t\t1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,\n\t\t1, 2, 1, 2, 3, 2, 290, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 297, 8,\n\t\t3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 304, 8, 3, 1, 3, 1, 3, 1, 3, 1,\n\t\t3, 3, 3, 310, 8, 3, 1, 3, 1, 3, 3, 3, 314, 8, 3, 1, 3, 1, 3, 1, 3, 3, 3,\n\t\t319, 8, 3, 1, 3, 3, 3, 322, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 329,\n\t\t8, 4, 1, 4, 3, 4, 332, 8, 4, 1, 5, 1, 5, 3, 5, 336, 8, 5, 1, 5, 1, 5, 1,\n\t\t5, 1, 5, 1, 6, 1, 6, 3, 6, 344, 8, 6, 1, 6, 1, 6, 3, 6, 348, 8, 6, 3, 6,\n\t\t350, 8, 6, 1, 7, 1, 7, 3, 7, 354, 8, 7, 1, 8, 1, 8, 3, 8, 358, 8, 8, 1,\n\t\t8, 1, 8, 3, 8, 362, 8, 8, 1, 8, 3, 8, 365, 8, 8, 1, 9, 1, 9, 1, 9, 1, 10,\n\t\t1, 10, 3, 10, 372, 8, 10, 1, 10, 1, 10, 1, 11, 1, 11, 3, 11, 378, 8, 11,\n\t\t1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 384, 8, 11, 1, 11, 1, 11, 1, 11, 3,\n\t\t11, 389, 8, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11,\n\t\t398, 8, 11, 10, 11, 12, 11, 401, 9, 11, 1, 11, 1, 11, 1, 11, 3, 11, 406,\n\t\t8, 11, 1, 12, 1, 12, 3, 12, 410, 8, 12, 1, 12, 1, 12, 3, 12, 414, 8, 12,\n\t\t1, 12, 3, 12, 417, 8, 12, 1, 13, 1, 13, 3, 13, 421, 8, 13, 1, 13, 1, 13,\n\t\t1, 13, 1, 13, 3, 13, 427, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 432, 8, 13,\n\t\t1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 439, 8, 13, 10, 13, 12, 13, 442,\n\t\t9, 13, 1, 13, 1, 13, 5, 13, 446, 8, 13, 10, 13, 12, 13, 449, 9, 13, 1,\n\t\t13, 1, 13, 1, 13, 3, 13, 454, 8, 13, 1, 13, 1, 13, 3, 13, 458, 8, 13, 1,\n\t\t14, 1, 14, 3, 14, 462, 8, 14, 1, 14, 5, 14, 465, 8, 14, 10, 14, 12, 14,\n\t\t468, 9, 14, 1, 15, 4, 15, 471, 8, 15, 11, 15, 12, 15, 472, 1, 15, 1, 15,\n\t\t1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 485, 8,\n\t\t15, 1, 16, 1, 16, 3, 16, 489, 8, 16, 1, 16, 1, 16, 1, 16, 3, 16, 494, 8,\n\t\t16, 1, 16, 3, 16, 497, 8, 16, 1, 16, 3, 16, 500, 8, 16, 1, 16, 1, 16, 1,\n\t\t16, 3, 16, 505, 8, 16, 1, 16, 3, 16, 508, 8, 16, 1, 16, 1, 16, 1, 16, 1,\n\t\t16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 522,\n\t\t8, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 529, 8, 16, 1, 16, 1,\n\t\t16, 1, 16, 1, 16, 1, 16, 3, 16, 536, 8, 16, 3, 16, 538, 8, 16, 1, 17, 3,\n\t\t17, 541, 8, 17, 1, 17, 1, 17, 1, 18, 1, 18, 3, 18, 547, 8, 18, 1, 18, 1,\n\t\t18, 1, 18, 3, 18, 552, 8, 18, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 558, 8,\n\t\t18, 10, 18, 12, 18, 561, 9, 18, 1, 18, 1, 18, 3, 18, 565, 8, 18, 1, 18,\n\t\t1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 5,\n\t\t18, 578, 8, 18, 10, 18, 12, 18, 581, 9, 18, 1, 18, 1, 18, 1, 18, 3, 18,\n\t\t586, 8, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 594, 8, 19,\n\t\t10, 19, 12, 19, 597, 9, 19, 1, 19, 1, 19, 3, 19, 601, 8, 19, 1, 19, 1,\n\t\t19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 611, 8, 19, 1, 19,\n\t\t1, 19, 5, 19, 615, 8, 19, 10, 19, 12, 19, 618, 9, 19, 1, 19, 3, 19, 621,\n\t\t8, 19, 1, 19, 1, 19, 1, 19, 3, 19, 626, 8, 19, 3, 19, 628, 8, 19, 1, 20,\n\t\t1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 3, 21, 636, 8, 21, 1, 21, 1, 21, 1,\n\t\t21, 1, 21, 3, 21, 642, 8, 21, 1, 21, 1, 21, 1, 21, 3, 21, 647, 8, 21, 1,\n\t\t21, 1, 21, 1, 21, 1, 21, 1, 21, 3, 21, 654, 8, 21, 1, 21, 1, 21, 1, 21,\n\t\t1, 21, 1, 21, 1, 21, 1, 21, 5, 21, 663, 8, 21, 10, 21, 12, 21, 666, 9,\n\t\t21, 3, 21, 668, 8, 21, 3, 21, 670, 8, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1,\n\t\t21, 3, 21, 677, 8, 21, 1, 21, 1, 21, 3, 21, 681, 8, 21, 1, 21, 1, 21, 1,\n\t\t21, 1, 21, 1, 21, 3, 21, 688, 8, 21, 1, 21, 1, 21, 4, 21, 692, 8, 21, 11,\n\t\t21, 12, 21, 693, 1, 21, 1, 21, 1, 22, 1, 22, 3, 22, 700, 8, 22, 1, 22,\n\t\t1, 22, 1, 22, 1, 22, 3, 22, 706, 8, 22, 1, 22, 1, 22, 1, 22, 3, 22, 711,\n\t\t8, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 5, 22, 718, 8, 22, 10, 22, 12,\n\t\t22, 721, 9, 22, 1, 22, 1, 22, 3, 22, 725, 8, 22, 1, 22, 1, 22, 1, 22, 1,\n\t\t23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 3, 23, 736, 8, 23, 1, 23, 1, 23,\n\t\t1, 23, 3, 23, 741, 8, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1,\n\t\t23, 5, 23, 750, 8, 23, 10, 23, 12, 23, 753, 9, 23, 1, 23, 1, 23, 3, 23,\n\t\t757, 8, 23, 1, 24, 1, 24, 3, 24, 761, 8, 24, 1, 24, 1, 24, 1, 24, 1, 24,\n\t\t1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 775, 8,\n\t\t24, 10, 24, 12, 24, 778, 9, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 5, 25,\n\t\t785, 8, 25, 10, 25, 12, 25, 788, 9, 25, 1, 25, 1, 25, 3, 25, 792, 8, 25,\n\t\t1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 3, 26, 800, 8, 26, 1, 26, 1,\n\t\t26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 5, 27, 810, 8, 27, 10, 27,\n\t\t12, 27, 813, 9, 27, 1, 27, 1, 27, 3, 27, 817, 8, 27, 1, 27, 1, 27, 1, 27,\n\t\t1, 27, 1, 27, 1, 28, 3, 28, 825, 8, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1,\n\t\t28, 3, 28, 832, 8, 28, 1, 28, 3, 28, 835, 8, 28, 1, 29, 3, 29, 838, 8,\n\t\t29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 3, 29, 845, 8, 29, 1, 29, 3, 29,\n\t\t848, 8, 29, 1, 29, 3, 29, 851, 8, 29, 1, 29, 3, 29, 854, 8, 29, 1, 30,\n\t\t1, 30, 3, 30, 858, 8, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 3,\n\t\t31, 866, 8, 31, 1, 31, 1, 31, 1, 31, 3, 31, 871, 8, 31, 1, 31, 1, 31, 1,\n\t\t32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 881, 8, 32, 1, 32, 1, 32,\n\t\t1, 32, 3, 32, 886, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1,\n\t\t32, 3, 32, 895, 8, 32, 1, 32, 1, 32, 1, 32, 5, 32, 900, 8, 32, 10, 32,\n\t\t12, 32, 903, 9, 32, 1, 32, 3, 32, 906, 8, 32, 1, 32, 1, 32, 3, 32, 910,\n\t\t8, 32, 1, 32, 3, 32, 913, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 5, 32, 919,\n\t\t8, 32, 10, 32, 12, 32, 922, 9, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1,\n\t\t32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 934, 8, 32, 1, 32, 3, 32, 937, 8,\n\t\t32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 945, 8, 32, 1, 32,\n\t\t1, 32, 1, 32, 1, 32, 1, 32, 4, 32, 952, 8, 32, 11, 32, 12, 32, 953, 1,\n\t\t32, 1, 32, 3, 32, 958, 8, 32, 1, 32, 1, 32, 1, 32, 3, 32, 963, 8, 32, 1,\n\t\t32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32,\n\t\t1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1,\n\t\t32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 993, 8, 32, 1, 32,\n\t\t1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1005,\n\t\t8, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1010, 8, 32, 1, 32, 1, 32, 1, 32, 1,\n\t\t32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1022, 8, 32, 1, 32,\n\t\t1, 32, 1, 32, 1, 32, 3, 32, 1028, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1,\n\t\t32, 3, 32, 1035, 8, 32, 1, 32, 1, 32, 3, 32, 1039, 8, 32, 1, 32, 1, 32,\n\t\t1, 32, 1, 32, 1, 32, 1, 32, 5, 32, 1047, 8, 32, 10, 32, 12, 32, 1050, 9,\n\t\t32, 3, 32, 1052, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1058, 8, 32,\n\t\t1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 1064, 8, 32, 1, 32, 1, 32, 1, 32, 1,\n\t\t32, 1, 32, 5, 32, 1071, 8, 32, 10, 32, 12, 32, 1074, 9, 32, 3, 32, 1076,\n\t\t8, 32, 1, 32, 1, 32, 3, 32, 1080, 8, 32, 5, 32, 1082, 8, 32, 10, 32, 12,\n\t\t32, 1085, 9, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 1093,\n\t\t8, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 3, 35, 1100, 8, 35, 1, 35, 1,\n\t\t35, 1, 35, 1, 35, 1, 35, 3, 35, 1107, 8, 35, 1, 35, 1, 35, 1, 35, 1, 35,\n\t\t3, 35, 1113, 8, 35, 1, 35, 1, 35, 1, 35, 3, 35, 1118, 8, 35, 1, 35, 1,\n\t\t35, 1, 35, 1, 35, 5, 35, 1124, 8, 35, 10, 35, 12, 35, 1127, 9, 35, 1, 35,\n\t\t1, 35, 3, 35, 1131, 8, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 1138,\n\t\t8, 35, 10, 35, 12, 35, 1141, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35,\n\t\t1, 35, 5, 35, 1149, 8, 35, 10, 35, 12, 35, 1152, 9, 35, 1, 35, 1, 35, 5,\n\t\t35, 1156, 8, 35, 10, 35, 12, 35, 1159, 9, 35, 1, 35, 3, 35, 1162, 8, 35,\n\t\t1, 35, 3, 35, 1165, 8, 35, 1, 35, 1, 35, 3, 35, 1169, 8, 35, 1, 35, 3,\n\t\t35, 1172, 8, 35, 1, 36, 1, 36, 1, 36, 1, 36, 5, 36, 1178, 8, 36, 10, 36,\n\t\t12, 36, 1181, 9, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 1189,\n\t\t8, 37, 10, 37, 12, 37, 1192, 9, 37, 1, 37, 1, 37, 1, 37, 3, 37, 1197, 8,\n\t\t37, 3, 37, 1199, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37,\n\t\t1207, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 1214, 8, 37, 1,\n\t\t37, 1, 37, 1, 37, 5, 37, 1219, 8, 37, 10, 37, 12, 37, 1222, 9, 37, 1, 37,\n\t\t1, 37, 3, 37, 1226, 8, 37, 3, 37, 1228, 8, 37, 1, 38, 1, 38, 1, 38, 1,\n\t\t38, 3, 38, 1234, 8, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38,\n\t\t3, 38, 1243, 8, 38, 1, 39, 1, 39, 1, 39, 3, 39, 1248, 8, 39, 1, 40, 1,\n\t\t40, 1, 40, 1, 40, 1, 40, 3, 40, 1255, 8, 40, 1, 40, 1, 40, 3, 40, 1259,\n\t\t8, 40, 3, 40, 1261, 8, 40, 1, 41, 3, 41, 1264, 8, 41, 1, 41, 1, 41, 1,\n\t\t41, 1, 41, 5, 41, 1270, 8, 41, 10, 41, 12, 41, 1273, 9, 41, 1, 41, 3, 41,\n\t\t1276, 8, 41, 1, 41, 3, 41, 1279, 8, 41, 1, 42, 1, 42, 1, 42, 1, 42, 3,\n\t\t42, 1285, 8, 42, 5, 42, 1287, 8, 42, 10, 42, 12, 42, 1290, 9, 42, 1, 43,\n\t\t1, 43, 3, 43, 1294, 8, 43, 1, 43, 1, 43, 1, 43, 5, 43, 1299, 8, 43, 10,\n\t\t43, 12, 43, 1302, 9, 43, 1, 43, 1, 43, 1, 43, 1, 43, 5, 43, 1308, 8, 43,\n\t\t10, 43, 12, 43, 1311, 9, 43, 1, 43, 3, 43, 1314, 8, 43, 3, 43, 1316, 8,\n\t\t43, 1, 43, 1, 43, 3, 43, 1320, 8, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43,\n\t\t5, 43, 1327, 8, 43, 10, 43, 12, 43, 1330, 9, 43, 1, 43, 1, 43, 3, 43, 1334,\n\t\t8, 43, 3, 43, 1336, 8, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1,\n\t\t43, 1, 43, 1, 43, 5, 43, 1347, 8, 43, 10, 43, 12, 43, 1350, 9, 43, 3, 43,\n\t\t1352, 8, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 5, 43, 1359, 8, 43, 10,\n\t\t43, 12, 43, 1362, 9, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 5, 43,\n\t\t1370, 8, 43, 10, 43, 12, 43, 1373, 9, 43, 1, 43, 1, 43, 5, 43, 1377, 8,\n\t\t43, 10, 43, 12, 43, 1380, 9, 43, 3, 43, 1382, 8, 43, 1, 44, 1, 44, 1, 45,\n\t\t3, 45, 1387, 8, 45, 1, 45, 1, 45, 3, 45, 1391, 8, 45, 1, 45, 3, 45, 1394,\n\t\t8, 45, 1, 46, 3, 46, 1397, 8, 46, 1, 46, 1, 46, 1, 46, 3, 46, 1402, 8,\n\t\t46, 1, 46, 1, 46, 3, 46, 1406, 8, 46, 1, 46, 4, 46, 1409, 8, 46, 11, 46,\n\t\t12, 46, 1410, 1, 46, 3, 46, 1414, 8, 46, 1, 46, 3, 46, 1417, 8, 46, 1,\n\t\t47, 1, 47, 1, 47, 3, 47, 1422, 8, 47, 1, 47, 1, 47, 3, 47, 1426, 8, 47,\n\t\t1, 47, 3, 47, 1429, 8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 1436,\n\t\t8, 47, 1, 47, 1, 47, 1, 47, 3, 47, 1441, 8, 47, 1, 47, 1, 47, 1, 47, 1,\n\t\t47, 1, 47, 5, 47, 1448, 8, 47, 10, 47, 12, 47, 1451, 9, 47, 1, 47, 1, 47,\n\t\t3, 47, 1455, 8, 47, 1, 47, 3, 47, 1458, 8, 47, 1, 47, 1, 47, 1, 47, 1,\n\t\t47, 5, 47, 1464, 8, 47, 10, 47, 12, 47, 1467, 9, 47, 1, 47, 3, 47, 1470,\n\t\t8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 1478, 8, 47, 1,\n\t\t47, 3, 47, 1481, 8, 47, 3, 47, 1483, 8, 47, 1, 48, 1, 48, 1, 48, 1, 48,\n\t\t1, 48, 1, 48, 1, 48, 3, 48, 1492, 8, 48, 1, 48, 3, 48, 1495, 8, 48, 3,\n\t\t48, 1497, 8, 48, 1, 49, 1, 49, 3, 49, 1501, 8, 49, 1, 49, 1, 49, 3, 49,\n\t\t1505, 8, 49, 1, 49, 1, 49, 3, 49, 1509, 8, 49, 1, 49, 3, 49, 1512, 8, 49,\n\t\t1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 5, 50, 1521, 8, 50, 10,\n\t\t50, 12, 50, 1524, 9, 50, 1, 50, 1, 50, 3, 50, 1528, 8, 50, 1, 51, 1, 51,\n\t\t3, 51, 1532, 8, 51, 1, 51, 1, 51, 3, 51, 1536, 8, 51, 1, 52, 3, 52, 1539,\n\t\t8, 52, 1, 52, 1, 52, 1, 52, 3, 52, 1544, 8, 52, 1, 52, 1, 52, 1, 52, 1,\n\t\t52, 1, 52, 1, 52, 1, 52, 5, 52, 1553, 8, 52, 10, 52, 12, 52, 1556, 9, 52,\n\t\t1, 52, 3, 52, 1559, 8, 52, 3, 52, 1561, 8, 52, 1, 52, 1, 52, 3, 52, 1565,\n\t\t8, 52, 1, 52, 3, 52, 1568, 8, 52, 1, 53, 1, 53, 1, 53, 5, 53, 1573, 8,\n\t\t53, 10, 53, 12, 53, 1576, 9, 53, 1, 54, 1, 54, 3, 54, 1580, 8, 54, 1, 54,\n\t\t1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 5, 55, 1589, 8, 55, 10, 55, 12,\n\t\t55, 1592, 9, 55, 1, 55, 1, 55, 1, 56, 3, 56, 1597, 8, 56, 1, 56, 1, 56,\n\t\t1, 56, 3, 56, 1602, 8, 56, 1, 56, 1, 56, 1, 56, 1, 56, 3, 56, 1608, 8,\n\t\t56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 3, 56, 1615, 8, 56, 1, 56, 1, 56,\n\t\t1, 56, 5, 56, 1620, 8, 56, 10, 56, 12, 56, 1623, 9, 56, 1, 56, 1, 56, 3,\n\t\t56, 1627, 8, 56, 1, 56, 3, 56, 1630, 8, 56, 1, 56, 3, 56, 1633, 8, 56,\n\t\t1, 56, 3, 56, 1636, 8, 56, 1, 57, 1, 57, 1, 57, 3, 57, 1641, 8, 57, 1,\n\t\t57, 1, 57, 1, 57, 3, 57, 1646, 8, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57,\n\t\t3, 57, 1653, 8, 57, 1, 58, 1, 58, 3, 58, 1657, 8, 58, 1, 58, 1, 58, 3,\n\t\t58, 1661, 8, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60,\n\t\t3, 60, 1671, 8, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 5, 60, 1678, 8,\n\t\t60, 10, 60, 12, 60, 1681, 9, 60, 3, 60, 1683, 8, 60, 1, 60, 1, 60, 1, 60,\n\t\t1, 60, 1, 60, 5, 60, 1690, 8, 60, 10, 60, 12, 60, 1693, 9, 60, 1, 60, 3,\n\t\t60, 1696, 8, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 1704,\n\t\t8, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 1711, 8, 61, 10, 61, 12,\n\t\t61, 1714, 9, 61, 3, 61, 1716, 8, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61,\n\t\t5, 61, 1723, 8, 61, 10, 61, 12, 61, 1726, 9, 61, 3, 61, 1728, 8, 61, 1,\n\t\t61, 3, 61, 1731, 8, 61, 1, 61, 3, 61, 1734, 8, 61, 1, 62, 1, 62, 1, 62,\n\t\t1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 1744, 8, 62, 1, 63, 1, 63, 1,\n\t\t63, 1, 63, 1, 63, 1, 63, 1, 63, 3, 63, 1753, 8, 63, 1, 64, 1, 64, 1, 64,\n\t\t1, 64, 1, 64, 5, 64, 1760, 8, 64, 10, 64, 12, 64, 1763, 9, 64, 1, 64, 3,\n\t\t64, 1766, 8, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 3, 65, 1773, 8, 65,\n\t\t1, 65, 1, 65, 1, 65, 5, 65, 1778, 8, 65, 10, 65, 12, 65, 1781, 9, 65, 1,\n\t\t65, 3, 65, 1784, 8, 65, 1, 65, 1, 65, 3, 65, 1788, 8, 65, 1, 66, 1, 66,\n\t\t1, 66, 1, 66, 1, 66, 5, 66, 1795, 8, 66, 10, 66, 12, 66, 1798, 9, 66, 1,\n\t\t66, 3, 66, 1801, 8, 66, 1, 66, 1, 66, 3, 66, 1805, 8, 66, 1, 66, 1, 66,\n\t\t1, 66, 3, 66, 1810, 8, 66, 1, 67, 1, 67, 3, 67, 1814, 8, 67, 1, 67, 1,\n\t\t67, 1, 67, 5, 67, 1819, 8, 67, 10, 67, 12, 67, 1822, 9, 67, 1, 68, 1, 68,\n\t\t1, 68, 1, 68, 1, 68, 5, 68, 1829, 8, 68, 10, 68, 12, 68, 1832, 9, 68, 1,\n\t\t69, 1, 69, 1, 69, 1, 69, 3, 69, 1838, 8, 69, 1, 70, 1, 70, 1, 70, 3, 70,\n\t\t1843, 8, 70, 1, 70, 3, 70, 1846, 8, 70, 1, 70, 1, 70, 3, 70, 1850, 8, 70,\n\t\t1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1,\n\t\t72, 1, 72, 3, 72, 1864, 8, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73,\n\t\t1, 73, 1, 73, 1, 73, 1, 73, 3, 73, 1876, 8, 73, 1, 74, 1, 74, 1, 74, 1,\n\t\t74, 1, 74, 1, 74, 1, 74, 3, 74, 1885, 8, 74, 1, 75, 1, 75, 1, 75, 1, 75,\n\t\t1, 75, 1, 75, 1, 75, 3, 75, 1894, 8, 75, 1, 75, 1, 75, 3, 75, 1898, 8,\n\t\t75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 3, 75, 1908,\n\t\t8, 75, 1, 75, 3, 75, 1911, 8, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1,\n\t\t75, 1, 75, 3, 75, 1920, 8, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75,\n\t\t1, 75, 3, 75, 1929, 8, 75, 1, 75, 3, 75, 1932, 8, 75, 1, 75, 1, 75, 1,\n\t\t75, 1, 75, 3, 75, 1938, 8, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75,\n\t\t1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 3, 75, 1952, 8, 75, 1, 75, 1,\n\t\t75, 3, 75, 1956, 8, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75,\n\t\t1, 75, 1, 75, 3, 75, 1967, 8, 75, 1, 75, 1, 75, 1, 75, 3, 75, 1972, 8,\n\t\t75, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 4, 78,\n\t\t1983, 8, 78, 11, 78, 12, 78, 1984, 1, 79, 1, 79, 1, 79, 4, 79, 1990, 8,\n\t\t79, 11, 79, 12, 79, 1991, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 3,\n\t\t81, 2000, 8, 81, 1, 81, 1, 81, 1, 81, 3, 81, 2005, 8, 81, 5, 81, 2007,\n\t\t8, 81, 10, 81, 12, 81, 2010, 9, 81, 1, 82, 1, 82, 1, 83, 1, 83, 1, 84,\n\t\t1, 84, 1, 85, 1, 85, 1, 86, 1, 86, 3, 86, 2022, 8, 86, 1, 87, 1, 87, 1,\n\t\t88, 1, 88, 1, 89, 1, 89, 1, 90, 1, 90, 1, 91, 1, 91, 1, 92, 1, 92, 1, 93,\n\t\t1, 93, 1, 94, 1, 94, 1, 95, 1, 95, 1, 96, 1, 96, 1, 97, 1, 97, 1, 98, 1,\n\t\t98, 1, 99, 1, 99, 1, 100, 1, 100, 1, 101, 1, 101, 1, 102, 1, 102, 1, 103,\n\t\t1, 103, 1, 104, 1, 104, 1, 105, 1, 105, 1, 106, 1, 106, 1, 107, 1, 107,\n\t\t1, 108, 1, 108, 1, 109, 1, 109, 1, 110, 1, 110, 1, 111, 1, 111, 1, 112,\n\t\t1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 3, 112, 2081, 8, 112, 1,\n\t\t112, 2, 440, 472, 1, 64, 113, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22,\n\t\t24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58,\n\t\t60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94,\n\t\t96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124,\n\t\t126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154,\n\t\t156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184,\n\t\t186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214,\n\t\t216, 218, 220, 222, 224, 0, 28, 3, 0, 58, 58, 69, 69, 82, 82, 2, 0, 47,\n\t\t47, 66, 66, 1, 0, 133, 134, 2, 0, 146, 146, 171, 171, 1, 0, 8, 9, 2, 0,\n\t\t59, 59, 141, 141, 2, 0, 56, 56, 104, 104, 2, 0, 58, 58, 82, 82, 5, 0, 25,\n\t\t25, 72, 72, 81, 81, 122, 122, 126, 126, 4, 0, 84, 84, 132, 132, 138, 138,\n\t\t145, 145, 2, 0, 7, 7, 12, 13, 1, 0, 14, 17, 1, 0, 18, 21, 4, 0, 77, 77,\n\t\t97, 97, 99, 99, 118, 118, 3, 0, 25, 25, 72, 72, 126, 126, 5, 0, 52, 54,\n\t\t104, 104, 172, 173, 186, 186, 188, 189, 2, 0, 29, 29, 62, 62, 3, 0, 128,\n\t\t128, 154, 154, 179, 179, 2, 0, 5, 5, 106, 106, 1, 0, 176, 177, 2, 0, 34,\n\t\t34, 60, 60, 2, 0, 151, 151, 162, 162, 2, 0, 159, 159, 166, 166, 2, 0, 160,\n\t\t160, 167, 168, 2, 0, 161, 161, 163, 163, 2, 0, 8, 10, 102, 102, 2, 0, 185,\n\t\t185, 188, 188, 2, 0, 25, 123, 125, 180, 2367, 0, 229, 1, 0, 0, 0, 2, 237,\n\t\t1, 0, 0, 0, 4, 263, 1, 0, 0, 0, 6, 291, 1, 0, 0, 0, 8, 323, 1, 0, 0, 0,\n\t\t10, 333, 1, 0, 0, 0, 12, 341, 1, 0, 0, 0, 14, 351, 1, 0, 0, 0, 16, 355,\n\t\t1, 0, 0, 0, 18, 366, 1, 0, 0, 0, 20, 369, 1, 0, 0, 0, 22, 375, 1, 0, 0,\n\t\t0, 24, 409, 1, 0, 0, 0, 26, 418, 1, 0, 0, 0, 28, 459, 1, 0, 0, 0, 30, 470,\n\t\t1, 0, 0, 0, 32, 488, 1, 0, 0, 0, 34, 540, 1, 0, 0, 0, 36, 546, 1, 0, 0,\n\t\t0, 38, 587, 1, 0, 0, 0, 40, 629, 1, 0, 0, 0, 42, 633, 1, 0, 0, 0, 44, 697,\n\t\t1, 0, 0, 0, 46, 729, 1, 0, 0, 0, 48, 758, 1, 0, 0, 0, 50, 779, 1, 0, 0,\n\t\t0, 52, 793, 1, 0, 0, 0, 54, 804, 1, 0, 0, 0, 56, 824, 1, 0, 0, 0, 58, 837,\n\t\t1, 0, 0, 0, 60, 855, 1, 0, 0, 0, 62, 861, 1, 0, 0, 0, 64, 962, 1, 0, 0,\n\t\t0, 66, 1086, 1, 0, 0, 0, 68, 1096, 1, 0, 0, 0, 70, 1099, 1, 0, 0, 0, 72,\n\t\t1173, 1, 0, 0, 0, 74, 1182, 1, 0, 0, 0, 76, 1229, 1, 0, 0, 0, 78, 1247,\n\t\t1, 0, 0, 0, 80, 1249, 1, 0, 0, 0, 82, 1263, 1, 0, 0, 0, 84, 1280, 1, 0,\n\t\t0, 0, 86, 1381, 1, 0, 0, 0, 88, 1383, 1, 0, 0, 0, 90, 1386, 1, 0, 0, 0,\n\t\t92, 1396, 1, 0, 0, 0, 94, 1482, 1, 0, 0, 0, 96, 1496, 1, 0, 0, 0, 98, 1511,\n\t\t1, 0, 0, 0, 100, 1527, 1, 0, 0, 0, 102, 1535, 1, 0, 0, 0, 104, 1538, 1,\n\t\t0, 0, 0, 106, 1569, 1, 0, 0, 0, 108, 1579, 1, 0, 0, 0, 110, 1584, 1, 0,\n\t\t0, 0, 112, 1596, 1, 0, 0, 0, 114, 1640, 1, 0, 0, 0, 116, 1654, 1, 0, 0,\n\t\t0, 118, 1662, 1, 0, 0, 0, 120, 1668, 1, 0, 0, 0, 122, 1699, 1, 0, 0, 0,\n\t\t124, 1735, 1, 0, 0, 0, 126, 1745, 1, 0, 0, 0, 128, 1754, 1, 0, 0, 0, 130,\n\t\t1769, 1, 0, 0, 0, 132, 1789, 1, 0, 0, 0, 134, 1811, 1, 0, 0, 0, 136, 1823,\n\t\t1, 0, 0, 0, 138, 1833, 1, 0, 0, 0, 140, 1839, 1, 0, 0, 0, 142, 1851, 1,\n\t\t0, 0, 0, 144, 1863, 1, 0, 0, 0, 146, 1875, 1, 0, 0, 0, 148, 1884, 1, 0,\n\t\t0, 0, 150, 1971, 1, 0, 0, 0, 152, 1973, 1, 0, 0, 0, 154, 1976, 1, 0, 0,\n\t\t0, 156, 1979, 1, 0, 0, 0, 158, 1986, 1, 0, 0, 0, 160, 1993, 1, 0, 0, 0,\n\t\t162, 1997, 1, 0, 0, 0, 164, 2011, 1, 0, 0, 0, 166, 2013, 1, 0, 0, 0, 168,\n\t\t2015, 1, 0, 0, 0, 170, 2017, 1, 0, 0, 0, 172, 2021, 1, 0, 0, 0, 174, 2023,\n\t\t1, 0, 0, 0, 176, 2025, 1, 0, 0, 0, 178, 2027, 1, 0, 0, 0, 180, 2029, 1,\n\t\t0, 0, 0, 182, 2031, 1, 0, 0, 0, 184, 2033, 1, 0, 0, 0, 186, 2035, 1, 0,\n\t\t0, 0, 188, 2037, 1, 0, 0, 0, 190, 2039, 1, 0, 0, 0, 192, 2041, 1, 0, 0,\n\t\t0, 194, 2043, 1, 0, 0, 0, 196, 2045, 1, 0, 0, 0, 198, 2047, 1, 0, 0, 0,\n\t\t200, 2049, 1, 0, 0, 0, 202, 2051, 1, 0, 0, 0, 204, 2053, 1, 0, 0, 0, 206,\n\t\t2055, 1, 0, 0, 0, 208, 2057, 1, 0, 0, 0, 210, 2059, 1, 0, 0, 0, 212, 2061,\n\t\t1, 0, 0, 0, 214, 2063, 1, 0, 0, 0, 216, 2065, 1, 0, 0, 0, 218, 2067, 1,\n\t\t0, 0, 0, 220, 2069, 1, 0, 0, 0, 222, 2071, 1, 0, 0, 0, 224, 2080, 1, 0,\n\t\t0, 0, 226, 228, 3, 2, 1, 0, 227, 226, 1, 0, 0, 0, 228, 231, 1, 0, 0, 0,\n\t\t229, 227, 1, 0, 0, 0, 229, 230, 1, 0, 0, 0, 230, 232, 1, 0, 0, 0, 231,\n\t\t229, 1, 0, 0, 0, 232, 233, 5, 0, 0, 1, 233, 1, 1, 0, 0, 0, 234, 236, 5,\n\t\t1, 0, 0, 235, 234, 1, 0, 0, 0, 236, 239, 1, 0, 0, 0, 237, 235, 1, 0, 0,\n\t\t0, 237, 238, 1, 0, 0, 0, 238, 240, 1, 0, 0, 0, 239, 237, 1, 0, 0, 0, 240,\n\t\t249, 3, 4, 2, 0, 241, 243, 5, 1, 0, 0, 242, 241, 1, 0, 0, 0, 243, 244,\n\t\t1, 0, 0, 0, 244, 242, 1, 0, 0, 0, 244, 245, 1, 0, 0, 0, 245, 246, 1, 0,\n\t\t0, 0, 246, 248, 3, 4, 2, 0, 247, 242, 1, 0, 0, 0, 248, 251, 1, 0, 0, 0,\n\t\t249, 247, 1, 0, 0, 0, 249, 250, 1, 0, 0, 0, 250, 255, 1, 0, 0, 0, 251,\n\t\t249, 1, 0, 0, 0, 252, 254, 5, 1, 0, 0, 253, 252, 1, 0, 0, 0, 254, 257,\n\t\t1, 0, 0, 0, 255, 253, 1, 0, 0, 0, 255, 256, 1, 0, 0, 0, 256, 3, 1, 0, 0,\n\t\t0, 257, 255, 1, 0, 0, 0, 258, 261, 5, 71, 0, 0, 259, 260, 5, 114, 0, 0,\n\t\t260, 262, 5, 111, 0, 0, 261, 259, 1, 0, 0, 0, 261, 262, 1, 0, 0, 0, 262,\n\t\t264, 1, 0, 0, 0, 263, 258, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 289,\n\t\t1, 0, 0, 0, 265, 290, 3, 6, 3, 0, 266, 290, 3, 8, 4, 0, 267, 290, 3, 10,\n\t\t5, 0, 268, 290, 3, 12, 6, 0, 269, 290, 3, 14, 7, 0, 270, 290, 3, 22, 11,\n\t\t0, 271, 290, 3, 26, 13, 0, 272, 290, 3, 42, 21, 0, 273, 290, 3, 44, 22,\n\t\t0, 274, 290, 3, 46, 23, 0, 275, 290, 3, 56, 28, 0, 276, 290, 3, 58, 29,\n\t\t0, 277, 290, 3, 60, 30, 0, 278, 290, 3, 62, 31, 0, 279, 290, 3, 70, 35,\n\t\t0, 280, 290, 3, 76, 38, 0, 281, 290, 3, 80, 40, 0, 282, 290, 3, 20, 10,\n\t\t0, 283, 290, 3, 16, 8, 0, 284, 290, 3, 18, 9, 0, 285, 290, 3, 82, 41, 0,\n\t\t286, 290, 3, 104, 52, 0, 287, 290, 3, 112, 56, 0, 288, 290, 3, 116, 58,\n\t\t0, 289, 265, 1, 0, 0, 0, 289, 266, 1, 0, 0, 0, 289, 267, 1, 0, 0, 0, 289,\n\t\t268, 1, 0, 0, 0, 289, 269, 1, 0, 0, 0, 289, 270, 1, 0, 0, 0, 289, 271,\n\t\t1, 0, 0, 0, 289, 272, 1, 0, 0, 0, 289, 273, 1, 0, 0, 0, 289, 274, 1, 0,\n\t\t0, 0, 289, 275, 1, 0, 0, 0, 289, 276, 1, 0, 0, 0, 289, 277, 1, 0, 0, 0,\n\t\t289, 278, 1, 0, 0, 0, 289, 279, 1, 0, 0, 0, 289, 280, 1, 0, 0, 0, 289,\n\t\t281, 1, 0, 0, 0, 289, 282, 1, 0, 0, 0, 289, 283, 1, 0, 0, 0, 289, 284,\n\t\t1, 0, 0, 0, 289, 285, 1, 0, 0, 0, 289, 286, 1, 0, 0, 0, 289, 287, 1, 0,\n\t\t0, 0, 289, 288, 1, 0, 0, 0, 290, 5, 1, 0, 0, 0, 291, 292, 5, 30, 0, 0,\n\t\t292, 296, 5, 132, 0, 0, 293, 294, 3, 182, 91, 0, 294, 295, 5, 2, 0, 0,\n\t\t295, 297, 1, 0, 0, 0, 296, 293, 1, 0, 0, 0, 296, 297, 1, 0, 0, 0, 297,\n\t\t298, 1, 0, 0, 0, 298, 321, 3, 184, 92, 0, 299, 309, 5, 121, 0, 0, 300,\n\t\t301, 5, 136, 0, 0, 301, 310, 3, 184, 92, 0, 302, 304, 5, 46, 0, 0, 303,\n\t\t302, 1, 0, 0, 0, 303, 304, 1, 0, 0, 0, 304, 305, 1, 0, 0, 0, 305, 306,\n\t\t3, 188, 94, 0, 306, 307, 5, 136, 0, 0, 307, 308, 3, 188, 94, 0, 308, 310,\n\t\t1, 0, 0, 0, 309, 300, 1, 0, 0, 0, 309, 303, 1, 0, 0, 0, 310, 322, 1, 0,\n\t\t0, 0, 311, 313, 5, 27, 0, 0, 312, 314, 5, 46, 0, 0, 313, 312, 1, 0, 0,\n\t\t0, 313, 314, 1, 0, 0, 0, 314, 315, 1, 0, 0, 0, 315, 322, 3, 28, 14, 0,\n\t\t316, 318, 5, 63, 0, 0, 317, 319, 5, 46, 0, 0, 318, 317, 1, 0, 0, 0, 318,\n\t\t319, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 322, 3, 188, 94, 0, 321, 299,\n\t\t1, 0, 0, 0, 321, 311, 1, 0, 0, 0, 321, 316, 1, 0, 0, 0, 322, 7, 1, 0, 0,\n\t\t0, 323, 331, 5, 31, 0, 0, 324, 332, 3, 182, 91, 0, 325, 326, 3, 182, 91,\n\t\t0, 326, 327, 5, 2, 0, 0, 327, 329, 1, 0, 0, 0, 328, 325, 1, 0, 0, 0, 328,\n\t\t329, 1, 0, 0, 0, 329, 330, 1, 0, 0, 0, 330, 332, 3, 186, 93, 0, 331, 324,\n\t\t1, 0, 0, 0, 331, 328, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 9, 1, 0, 0,\n\t\t0, 333, 335, 5, 35, 0, 0, 334, 336, 5, 55, 0, 0, 335, 334, 1, 0, 0, 0,\n\t\t335, 336, 1, 0, 0, 0, 336, 337, 1, 0, 0, 0, 337, 338, 3, 64, 32, 0, 338,\n\t\t339, 5, 33, 0, 0, 339, 340, 3, 182, 91, 0, 340, 11, 1, 0, 0, 0, 341, 343,\n\t\t5, 38, 0, 0, 342, 344, 7, 0, 0, 0, 343, 342, 1, 0, 0, 0, 343, 344, 1, 0,\n\t\t0, 0, 344, 349, 1, 0, 0, 0, 345, 347, 5, 137, 0, 0, 346, 348, 3, 208, 104,\n\t\t0, 347, 346, 1, 0, 0, 0, 347, 348, 1, 0, 0, 0, 348, 350, 1, 0, 0, 0, 349,\n\t\t345, 1, 0, 0, 0, 349, 350, 1, 0, 0, 0, 350, 13, 1, 0, 0, 0, 351, 353, 7,\n\t\t1, 0, 0, 352, 354, 5, 137, 0, 0, 353, 352, 1, 0, 0, 0, 353, 354, 1, 0,\n\t\t0, 0, 354, 15, 1, 0, 0, 0, 355, 357, 5, 126, 0, 0, 356, 358, 5, 137, 0,\n\t\t0, 357, 356, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 364, 1, 0, 0, 0, 359,\n\t\t361, 5, 136, 0, 0, 360, 362, 5, 129, 0, 0, 361, 360, 1, 0, 0, 0, 361, 362,\n\t\t1, 0, 0, 0, 362, 363, 1, 0, 0, 0, 363, 365, 3, 204, 102, 0, 364, 359, 1,\n\t\t0, 0, 0, 364, 365, 1, 0, 0, 0, 365, 17, 1, 0, 0, 0, 366, 367, 5, 129, 0,\n\t\t0, 367, 368, 3, 204, 102, 0, 368, 19, 1, 0, 0, 0, 369, 371, 5, 120, 0,\n\t\t0, 370, 372, 5, 129, 0, 0, 371, 370, 1, 0, 0, 0, 371, 372, 1, 0, 0, 0,\n\t\t372, 373, 1, 0, 0, 0, 373, 374, 3, 204, 102, 0, 374, 21, 1, 0, 0, 0, 375,\n\t\t377, 5, 50, 0, 0, 376, 378, 5, 140, 0, 0, 377, 376, 1, 0, 0, 0, 377, 378,\n\t\t1, 0, 0, 0, 378, 379, 1, 0, 0, 0, 379, 383, 5, 84, 0, 0, 380, 381, 5, 80,\n\t\t0, 0, 381, 382, 5, 102, 0, 0, 382, 384, 5, 70, 0, 0, 383, 380, 1, 0, 0,\n\t\t0, 383, 384, 1, 0, 0, 0, 384, 388, 1, 0, 0, 0, 385, 386, 3, 182, 91, 0,\n\t\t386, 387, 5, 2, 0, 0, 387, 389, 1, 0, 0, 0, 388, 385, 1, 0, 0, 0, 388,\n\t\t389, 1, 0, 0, 0, 389, 390, 1, 0, 0, 0, 390, 391, 3, 194, 97, 0, 391, 392,\n\t\t5, 107, 0, 0, 392, 393, 3, 184, 92, 0, 393, 394, 5, 3, 0, 0, 394, 399,\n\t\t3, 24, 12, 0, 395, 396, 5, 5, 0, 0, 396, 398, 3, 24, 12, 0, 397, 395, 1,\n\t\t0, 0, 0, 398, 401, 1, 0, 0, 0, 399, 397, 1, 0, 0, 0, 399, 400, 1, 0, 0,\n\t\t0, 400, 402, 1, 0, 0, 0, 401, 399, 1, 0, 0, 0, 402, 405, 5, 4, 0, 0, 403,\n\t\t404, 5, 148, 0, 0, 404, 406, 3, 64, 32, 0, 405, 403, 1, 0, 0, 0, 405, 406,\n\t\t1, 0, 0, 0, 406, 23, 1, 0, 0, 0, 407, 410, 3, 188, 94, 0, 408, 410, 3,\n\t\t64, 32, 0, 409, 407, 1, 0, 0, 0, 409, 408, 1, 0, 0, 0, 410, 413, 1, 0,\n\t\t0, 0, 411, 412, 5, 45, 0, 0, 412, 414, 3, 190, 95, 0, 413, 411, 1, 0, 0,\n\t\t0, 413, 414, 1, 0, 0, 0, 414, 416, 1, 0, 0, 0, 415, 417, 3, 142, 71, 0,\n\t\t416, 415, 1, 0, 0, 0, 416, 417, 1, 0, 0, 0, 417, 25, 1, 0, 0, 0, 418, 420,\n\t\t5, 50, 0, 0, 419, 421, 7, 2, 0, 0, 420, 419, 1, 0, 0, 0, 420, 421, 1, 0,\n\t\t0, 0, 421, 422, 1, 0, 0, 0, 422, 426, 5, 132, 0, 0, 423, 424, 5, 80, 0,\n\t\t0, 424, 425, 5, 102, 0, 0, 425, 427, 5, 70, 0, 0, 426, 423, 1, 0, 0, 0,\n\t\t426, 427, 1, 0, 0, 0, 427, 431, 1, 0, 0, 0, 428, 429, 3, 182, 91, 0, 429,\n\t\t430, 5, 2, 0, 0, 430, 432, 1, 0, 0, 0, 431, 428, 1, 0, 0, 0, 431, 432,\n\t\t1, 0, 0, 0, 432, 433, 1, 0, 0, 0, 433, 457, 3, 184, 92, 0, 434, 435, 5,\n\t\t3, 0, 0, 435, 440, 3, 28, 14, 0, 436, 437, 5, 5, 0, 0, 437, 439, 3, 28,\n\t\t14, 0, 438, 436, 1, 0, 0, 0, 439, 442, 1, 0, 0, 0, 440, 441, 1, 0, 0, 0,\n\t\t440, 438, 1, 0, 0, 0, 441, 447, 1, 0, 0, 0, 442, 440, 1, 0, 0, 0, 443,\n\t\t444, 5, 5, 0, 0, 444, 446, 3, 36, 18, 0, 445, 443, 1, 0, 0, 0, 446, 449,\n\t\t1, 0, 0, 0, 447, 445, 1, 0, 0, 0, 447, 448, 1, 0, 0, 0, 448, 450, 1, 0,\n\t\t0, 0, 449, 447, 1, 0, 0, 0, 450, 453, 5, 4, 0, 0, 451, 452, 5, 150, 0,\n\t\t0, 452, 454, 5, 185, 0, 0, 453, 451, 1, 0, 0, 0, 453, 454, 1, 0, 0, 0,\n\t\t454, 458, 1, 0, 0, 0, 455, 456, 5, 33, 0, 0, 456, 458, 3, 82, 41, 0, 457,\n\t\t434, 1, 0, 0, 0, 457, 455, 1, 0, 0, 0, 458, 27, 1, 0, 0, 0, 459, 461, 3,\n\t\t188, 94, 0, 460, 462, 3, 30, 15, 0, 461, 460, 1, 0, 0, 0, 461, 462, 1,\n\t\t0, 0, 0, 462, 466, 1, 0, 0, 0, 463, 465, 3, 32, 16, 0, 464, 463, 1, 0,\n\t\t0, 0, 465, 468, 1, 0, 0, 0, 466, 464, 1, 0, 0, 0, 466, 467, 1, 0, 0, 0,\n\t\t467, 29, 1, 0, 0, 0, 468, 466, 1, 0, 0, 0, 469, 471, 3, 178, 89, 0, 470,\n\t\t469, 1, 0, 0, 0, 471, 472, 1, 0, 0, 0, 472, 473, 1, 0, 0, 0, 472, 470,\n\t\t1, 0, 0, 0, 473, 484, 1, 0, 0, 0, 474, 475, 5, 3, 0, 0, 475, 476, 3, 34,\n\t\t17, 0, 476, 477, 5, 4, 0, 0, 477, 485, 1, 0, 0, 0, 478, 479, 5, 3, 0, 0,\n\t\t479, 480, 3, 34, 17, 0, 480, 481, 5, 5, 0, 0, 481, 482, 3, 34, 17, 0, 482,\n\t\t483, 5, 4, 0, 0, 483, 485, 1, 0, 0, 0, 484, 474, 1, 0, 0, 0, 484, 478,\n\t\t1, 0, 0, 0, 484, 485, 1, 0, 0, 0, 485, 31, 1, 0, 0, 0, 486, 487, 5, 49,\n\t\t0, 0, 487, 489, 3, 178, 89, 0, 488, 486, 1, 0, 0, 0, 488, 489, 1, 0, 0,\n\t\t0, 489, 537, 1, 0, 0, 0, 490, 491, 5, 113, 0, 0, 491, 493, 5, 95, 0, 0,\n\t\t492, 494, 3, 142, 71, 0, 493, 492, 1, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494,\n\t\t496, 1, 0, 0, 0, 495, 497, 3, 40, 20, 0, 496, 495, 1, 0, 0, 0, 496, 497,\n\t\t1, 0, 0, 0, 497, 499, 1, 0, 0, 0, 498, 500, 5, 36, 0, 0, 499, 498, 1, 0,\n\t\t0, 0, 499, 500, 1, 0, 0, 0, 500, 538, 1, 0, 0, 0, 501, 502, 5, 102, 0,\n\t\t0, 502, 505, 5, 104, 0, 0, 503, 505, 5, 140, 0, 0, 504, 501, 1, 0, 0, 0,\n\t\t504, 503, 1, 0, 0, 0, 505, 507, 1, 0, 0, 0, 506, 508, 3, 40, 20, 0, 507,\n\t\t506, 1, 0, 0, 0, 507, 508, 1, 0, 0, 0, 508, 538, 1, 0, 0, 0, 509, 510,\n\t\t5, 44, 0, 0, 510, 511, 5, 3, 0, 0, 511, 512, 3, 64, 32, 0, 512, 513, 5,\n\t\t4, 0, 0, 513, 538, 1, 0, 0, 0, 514, 521, 5, 56, 0, 0, 515, 522, 3, 34,\n\t\t17, 0, 516, 522, 3, 68, 34, 0, 517, 518, 5, 3, 0, 0, 518, 519, 3, 64, 32,\n\t\t0, 519, 520, 5, 4, 0, 0, 520, 522, 1, 0, 0, 0, 521, 515, 1, 0, 0, 0, 521,\n\t\t516, 1, 0, 0, 0, 521, 517, 1, 0, 0, 0, 522, 538, 1, 0, 0, 0, 523, 524,\n\t\t5, 45, 0, 0, 524, 538, 3, 190, 95, 0, 525, 538, 3, 38, 19, 0, 526, 527,\n\t\t5, 169, 0, 0, 527, 529, 5, 170, 0, 0, 528, 526, 1, 0, 0, 0, 528, 529, 1,\n\t\t0, 0, 0, 529, 530, 1, 0, 0, 0, 530, 531, 5, 33, 0, 0, 531, 532, 5, 3, 0,\n\t\t0, 532, 533, 3, 64, 32, 0, 533, 535, 5, 4, 0, 0, 534, 536, 7, 3, 0, 0,\n\t\t535, 534, 1, 0, 0, 0, 535, 536, 1, 0, 0, 0, 536, 538, 1, 0, 0, 0, 537,\n\t\t490, 1, 0, 0, 0, 537, 504, 1, 0, 0, 0, 537, 509, 1, 0, 0, 0, 537, 514,\n\t\t1, 0, 0, 0, 537, 523, 1, 0, 0, 0, 537, 525, 1, 0, 0, 0, 537, 528, 1, 0,\n\t\t0, 0, 538, 33, 1, 0, 0, 0, 539, 541, 7, 4, 0, 0, 540, 539, 1, 0, 0, 0,\n\t\t540, 541, 1, 0, 0, 0, 541, 542, 1, 0, 0, 0, 542, 543, 5, 186, 0, 0, 543,\n\t\t35, 1, 0, 0, 0, 544, 545, 5, 49, 0, 0, 545, 547, 3, 178, 89, 0, 546, 544,\n\t\t1, 0, 0, 0, 546, 547, 1, 0, 0, 0, 547, 585, 1, 0, 0, 0, 548, 549, 5, 113,\n\t\t0, 0, 549, 552, 5, 95, 0, 0, 550, 552, 5, 140, 0, 0, 551, 548, 1, 0, 0,\n\t\t0, 551, 550, 1, 0, 0, 0, 552, 553, 1, 0, 0, 0, 553, 554, 5, 3, 0, 0, 554,\n\t\t559, 3, 24, 12, 0, 555, 556, 5, 5, 0, 0, 556, 558, 3, 24, 12, 0, 557, 555,\n\t\t1, 0, 0, 0, 558, 561, 1, 0, 0, 0, 559, 557, 1, 0, 0, 0, 559, 560, 1, 0,\n\t\t0, 0, 560, 562, 1, 0, 0, 0, 561, 559, 1, 0, 0, 0, 562, 564, 5, 4, 0, 0,\n\t\t563, 565, 3, 40, 20, 0, 564, 563, 1, 0, 0, 0, 564, 565, 1, 0, 0, 0, 565,\n\t\t586, 1, 0, 0, 0, 566, 567, 5, 44, 0, 0, 567, 568, 5, 3, 0, 0, 568, 569,\n\t\t3, 64, 32, 0, 569, 570, 5, 4, 0, 0, 570, 586, 1, 0, 0, 0, 571, 572, 5,\n\t\t74, 0, 0, 572, 573, 5, 95, 0, 0, 573, 574, 5, 3, 0, 0, 574, 579, 3, 188,\n\t\t94, 0, 575, 576, 5, 5, 0, 0, 576, 578, 3, 188, 94, 0, 577, 575, 1, 0, 0,\n\t\t0, 578, 581, 1, 0, 0, 0, 579, 577, 1, 0, 0, 0, 579, 580, 1, 0, 0, 0, 580,\n\t\t582, 1, 0, 0, 0, 581, 579, 1, 0, 0, 0, 582, 583, 5, 4, 0, 0, 583, 584,\n\t\t3, 38, 19, 0, 584, 586, 1, 0, 0, 0, 585, 551, 1, 0, 0, 0, 585, 566, 1,\n\t\t0, 0, 0, 585, 571, 1, 0, 0, 0, 586, 37, 1, 0, 0, 0, 587, 588, 5, 117, 0,\n\t\t0, 588, 600, 3, 192, 96, 0, 589, 590, 5, 3, 0, 0, 590, 595, 3, 188, 94,\n\t\t0, 591, 592, 5, 5, 0, 0, 592, 594, 3, 188, 94, 0, 593, 591, 1, 0, 0, 0,\n\t\t594, 597, 1, 0, 0, 0, 595, 593, 1, 0, 0, 0, 595, 596, 1, 0, 0, 0, 596,\n\t\t598, 1, 0, 0, 0, 597, 595, 1, 0, 0, 0, 598, 599, 5, 4, 0, 0, 599, 601,\n\t\t1, 0, 0, 0, 600, 589, 1, 0, 0, 0, 600, 601, 1, 0, 0, 0, 601, 616, 1, 0,\n\t\t0, 0, 602, 603, 5, 107, 0, 0, 603, 610, 7, 5, 0, 0, 604, 605, 5, 131, 0,\n\t\t0, 605, 611, 7, 6, 0, 0, 606, 611, 5, 41, 0, 0, 607, 611, 5, 123, 0, 0,\n\t\t608, 609, 5, 101, 0, 0, 609, 611, 5, 26, 0, 0, 610, 604, 1, 0, 0, 0, 610,\n\t\t606, 1, 0, 0, 0, 610, 607, 1, 0, 0, 0, 610, 608, 1, 0, 0, 0, 611, 615,\n\t\t1, 0, 0, 0, 612, 613, 5, 99, 0, 0, 613, 615, 3, 178, 89, 0, 614, 602, 1,\n\t\t0, 0, 0, 614, 612, 1, 0, 0, 0, 615, 618, 1, 0, 0, 0, 616, 614, 1, 0, 0,\n\t\t0, 616, 617, 1, 0, 0, 0, 617, 627, 1, 0, 0, 0, 618, 616, 1, 0, 0, 0, 619,\n\t\t621, 5, 102, 0, 0, 620, 619, 1, 0, 0, 0, 620, 621, 1, 0, 0, 0, 621, 622,\n\t\t1, 0, 0, 0, 622, 625, 5, 57, 0, 0, 623, 624, 5, 86, 0, 0, 624, 626, 7,\n\t\t7, 0, 0, 625, 623, 1, 0, 0, 0, 625, 626, 1, 0, 0, 0, 626, 628, 1, 0, 0,\n\t\t0, 627, 620, 1, 0, 0, 0, 627, 628, 1, 0, 0, 0, 628, 39, 1, 0, 0, 0, 629,\n\t\t630, 5, 107, 0, 0, 630, 631, 5, 48, 0, 0, 631, 632, 7, 8, 0, 0, 632, 41,\n\t\t1, 0, 0, 0, 633, 635, 5, 50, 0, 0, 634, 636, 7, 2, 0, 0, 635, 634, 1, 0,\n\t\t0, 0, 635, 636, 1, 0, 0, 0, 636, 637, 1, 0, 0, 0, 637, 641, 5, 138, 0,\n\t\t0, 638, 639, 5, 80, 0, 0, 639, 640, 5, 102, 0, 0, 640, 642, 5, 70, 0, 0,\n\t\t641, 638, 1, 0, 0, 0, 641, 642, 1, 0, 0, 0, 642, 646, 1, 0, 0, 0, 643,\n\t\t644, 3, 182, 91, 0, 644, 645, 5, 2, 0, 0, 645, 647, 1, 0, 0, 0, 646, 643,\n\t\t1, 0, 0, 0, 646, 647, 1, 0, 0, 0, 647, 648, 1, 0, 0, 0, 648, 653, 3, 196,\n\t\t98, 0, 649, 654, 5, 37, 0, 0, 650, 654, 5, 28, 0, 0, 651, 652, 5, 89, 0,\n\t\t0, 652, 654, 5, 105, 0, 0, 653, 649, 1, 0, 0, 0, 653, 650, 1, 0, 0, 0,\n\t\t653, 651, 1, 0, 0, 0, 653, 654, 1, 0, 0, 0, 654, 669, 1, 0, 0, 0, 655,\n\t\t670, 5, 59, 0, 0, 656, 670, 5, 88, 0, 0, 657, 667, 5, 141, 0, 0, 658, 659,\n\t\t5, 105, 0, 0, 659, 664, 3, 188, 94, 0, 660, 661, 5, 5, 0, 0, 661, 663,\n\t\t3, 188, 94, 0, 662, 660, 1, 0, 0, 0, 663, 666, 1, 0, 0, 0, 664, 662, 1,\n\t\t0, 0, 0, 664, 665, 1, 0, 0, 0, 665, 668, 1, 0, 0, 0, 666, 664, 1, 0, 0,\n\t\t0, 667, 658, 1, 0, 0, 0, 667, 668, 1, 0, 0, 0, 668, 670, 1, 0, 0, 0, 669,\n\t\t655, 1, 0, 0, 0, 669, 656, 1, 0, 0, 0, 669, 657, 1, 0, 0, 0, 670, 671,\n\t\t1, 0, 0, 0, 671, 672, 5, 107, 0, 0, 672, 676, 3, 184, 92, 0, 673, 674,\n\t\t5, 73, 0, 0, 674, 675, 5, 64, 0, 0, 675, 677, 5, 127, 0, 0, 676, 673, 1,\n\t\t0, 0, 0, 676, 677, 1, 0, 0, 0, 677, 680, 1, 0, 0, 0, 678, 679, 5, 147,\n\t\t0, 0, 679, 681, 3, 64, 32, 0, 680, 678, 1, 0, 0, 0, 680, 681, 1, 0, 0,\n\t\t0, 681, 682, 1, 0, 0, 0, 682, 691, 5, 38, 0, 0, 683, 688, 3, 104, 52, 0,\n\t\t684, 688, 3, 70, 35, 0, 685, 688, 3, 56, 28, 0, 686, 688, 3, 82, 41, 0,\n\t\t687, 683, 1, 0, 0, 0, 687, 684, 1, 0, 0, 0, 687, 685, 1, 0, 0, 0, 687,\n\t\t686, 1, 0, 0, 0, 688, 689, 1, 0, 0, 0, 689, 690, 5, 1, 0, 0, 690, 692,\n\t\t1, 0, 0, 0, 691, 687, 1, 0, 0, 0, 692, 693, 1, 0, 0, 0, 693, 691, 1, 0,\n\t\t0, 0, 693, 694, 1, 0, 0, 0, 694, 695, 1, 0, 0, 0, 695, 696, 5, 66, 0, 0,\n\t\t696, 43, 1, 0, 0, 0, 697, 699, 5, 50, 0, 0, 698, 700, 7, 2, 0, 0, 699,\n\t\t698, 1, 0, 0, 0, 699, 700, 1, 0, 0, 0, 700, 701, 1, 0, 0, 0, 701, 705,\n\t\t5, 145, 0, 0, 702, 703, 5, 80, 0, 0, 703, 704, 5, 102, 0, 0, 704, 706,\n\t\t5, 70, 0, 0, 705, 702, 1, 0, 0, 0, 705, 706, 1, 0, 0, 0, 706, 710, 1, 0,\n\t\t0, 0, 707, 708, 3, 182, 91, 0, 708, 709, 5, 2, 0, 0, 709, 711, 1, 0, 0,\n\t\t0, 710, 707, 1, 0, 0, 0, 710, 711, 1, 0, 0, 0, 711, 712, 1, 0, 0, 0, 712,\n\t\t724, 3, 198, 99, 0, 713, 714, 5, 3, 0, 0, 714, 719, 3, 188, 94, 0, 715,\n\t\t716, 5, 5, 0, 0, 716, 718, 3, 188, 94, 0, 717, 715, 1, 0, 0, 0, 718, 721,\n\t\t1, 0, 0, 0, 719, 717, 1, 0, 0, 0, 719, 720, 1, 0, 0, 0, 720, 722, 1, 0,\n\t\t0, 0, 721, 719, 1, 0, 0, 0, 722, 723, 5, 4, 0, 0, 723, 725, 1, 0, 0, 0,\n\t\t724, 713, 1, 0, 0, 0, 724, 725, 1, 0, 0, 0, 725, 726, 1, 0, 0, 0, 726,\n\t\t727, 5, 33, 0, 0, 727, 728, 3, 82, 41, 0, 728, 45, 1, 0, 0, 0, 729, 730,\n\t\t5, 50, 0, 0, 730, 731, 5, 146, 0, 0, 731, 735, 5, 132, 0, 0, 732, 733,\n\t\t5, 80, 0, 0, 733, 734, 5, 102, 0, 0, 734, 736, 5, 70, 0, 0, 735, 732, 1,\n\t\t0, 0, 0, 735, 736, 1, 0, 0, 0, 736, 740, 1, 0, 0, 0, 737, 738, 3, 182,\n\t\t91, 0, 738, 739, 5, 2, 0, 0, 739, 741, 1, 0, 0, 0, 740, 737, 1, 0, 0, 0,\n\t\t740, 741, 1, 0, 0, 0, 741, 742, 1, 0, 0, 0, 742, 743, 3, 184, 92, 0, 743,\n\t\t744, 5, 142, 0, 0, 744, 756, 3, 200, 100, 0, 745, 746, 5, 3, 0, 0, 746,\n\t\t751, 3, 172, 86, 0, 747, 748, 5, 5, 0, 0, 748, 750, 3, 172, 86, 0, 749,\n\t\t747, 1, 0, 0, 0, 750, 753, 1, 0, 0, 0, 751, 749, 1, 0, 0, 0, 751, 752,\n\t\t1, 0, 0, 0, 752, 754, 1, 0, 0, 0, 753, 751, 1, 0, 0, 0, 754, 755, 5, 4,\n\t\t0, 0, 755, 757, 1, 0, 0, 0, 756, 745, 1, 0, 0, 0, 756, 757, 1, 0, 0, 0,\n\t\t757, 47, 1, 0, 0, 0, 758, 760, 5, 149, 0, 0, 759, 761, 5, 116, 0, 0, 760,\n\t\t759, 1, 0, 0, 0, 760, 761, 1, 0, 0, 0, 761, 762, 1, 0, 0, 0, 762, 763,\n\t\t3, 50, 25, 0, 763, 764, 5, 33, 0, 0, 764, 765, 5, 3, 0, 0, 765, 766, 3,\n\t\t82, 41, 0, 766, 776, 5, 4, 0, 0, 767, 768, 5, 5, 0, 0, 768, 769, 3, 50,\n\t\t25, 0, 769, 770, 5, 33, 0, 0, 770, 771, 5, 3, 0, 0, 771, 772, 3, 82, 41,\n\t\t0, 772, 773, 5, 4, 0, 0, 773, 775, 1, 0, 0, 0, 774, 767, 1, 0, 0, 0, 775,\n\t\t778, 1, 0, 0, 0, 776, 774, 1, 0, 0, 0, 776, 777, 1, 0, 0, 0, 777, 49, 1,\n\t\t0, 0, 0, 778, 776, 1, 0, 0, 0, 779, 791, 3, 184, 92, 0, 780, 781, 5, 3,\n\t\t0, 0, 781, 786, 3, 188, 94, 0, 782, 783, 5, 5, 0, 0, 783, 785, 3, 188,\n\t\t94, 0, 784, 782, 1, 0, 0, 0, 785, 788, 1, 0, 0, 0, 786, 784, 1, 0, 0, 0,\n\t\t786, 787, 1, 0, 0, 0, 787, 789, 1, 0, 0, 0, 788, 786, 1, 0, 0, 0, 789,\n\t\t790, 5, 4, 0, 0, 790, 792, 1, 0, 0, 0, 791, 780, 1, 0, 0, 0, 791, 792,\n\t\t1, 0, 0, 0, 792, 51, 1, 0, 0, 0, 793, 794, 3, 50, 25, 0, 794, 795, 5, 33,\n\t\t0, 0, 795, 796, 5, 3, 0, 0, 796, 797, 3, 164, 82, 0, 797, 799, 5, 139,\n\t\t0, 0, 798, 800, 5, 29, 0, 0, 799, 798, 1, 0, 0, 0, 799, 800, 1, 0, 0, 0,\n\t\t800, 801, 1, 0, 0, 0, 801, 802, 3, 166, 83, 0, 802, 803, 5, 4, 0, 0, 803,\n\t\t53, 1, 0, 0, 0, 804, 816, 3, 184, 92, 0, 805, 806, 5, 3, 0, 0, 806, 811,\n\t\t3, 188, 94, 0, 807, 808, 5, 5, 0, 0, 808, 810, 3, 188, 94, 0, 809, 807,\n\t\t1, 0, 0, 0, 810, 813, 1, 0, 0, 0, 811, 809, 1, 0, 0, 0, 811, 812, 1, 0,\n\t\t0, 0, 812, 814, 1, 0, 0, 0, 813, 811, 1, 0, 0, 0, 814, 815, 5, 4, 0, 0,\n\t\t815, 817, 1, 0, 0, 0, 816, 805, 1, 0, 0, 0, 816, 817, 1, 0, 0, 0, 817,\n\t\t818, 1, 0, 0, 0, 818, 819, 5, 33, 0, 0, 819, 820, 5, 3, 0, 0, 820, 821,\n\t\t3, 82, 41, 0, 821, 822, 5, 4, 0, 0, 822, 55, 1, 0, 0, 0, 823, 825, 3, 48,\n\t\t24, 0, 824, 823, 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 826, 1, 0, 0, 0,\n\t\t826, 827, 5, 59, 0, 0, 827, 828, 5, 75, 0, 0, 828, 831, 3, 114, 57, 0,\n\t\t829, 830, 5, 148, 0, 0, 830, 832, 3, 64, 32, 0, 831, 829, 1, 0, 0, 0, 831,\n\t\t832, 1, 0, 0, 0, 832, 834, 1, 0, 0, 0, 833, 835, 3, 72, 36, 0, 834, 833,\n\t\t1, 0, 0, 0, 834, 835, 1, 0, 0, 0, 835, 57, 1, 0, 0, 0, 836, 838, 3, 48,\n\t\t24, 0, 837, 836, 1, 0, 0, 0, 837, 838, 1, 0, 0, 0, 838, 839, 1, 0, 0, 0,\n\t\t839, 840, 5, 59, 0, 0, 840, 841, 5, 75, 0, 0, 841, 844, 3, 114, 57, 0,\n\t\t842, 843, 5, 148, 0, 0, 843, 845, 3, 64, 32, 0, 844, 842, 1, 0, 0, 0, 844,\n\t\t845, 1, 0, 0, 0, 845, 847, 1, 0, 0, 0, 846, 848, 3, 72, 36, 0, 847, 846,\n\t\t1, 0, 0, 0, 847, 848, 1, 0, 0, 0, 848, 853, 1, 0, 0, 0, 849, 851, 3, 136,\n\t\t68, 0, 850, 849, 1, 0, 0, 0, 850, 851, 1, 0, 0, 0, 851, 852, 1, 0, 0, 0,\n\t\t852, 854, 3, 138, 69, 0, 853, 850, 1, 0, 0, 0, 853, 854, 1, 0, 0, 0, 854,\n\t\t59, 1, 0, 0, 0, 855, 857, 5, 61, 0, 0, 856, 858, 5, 55, 0, 0, 857, 856,\n\t\t1, 0, 0, 0, 857, 858, 1, 0, 0, 0, 858, 859, 1, 0, 0, 0, 859, 860, 3, 182,\n\t\t91, 0, 860, 61, 1, 0, 0, 0, 861, 862, 5, 63, 0, 0, 862, 865, 7, 9, 0, 0,\n\t\t863, 864, 5, 80, 0, 0, 864, 866, 5, 70, 0, 0, 865, 863, 1, 0, 0, 0, 865,\n\t\t866, 1, 0, 0, 0, 866, 870, 1, 0, 0, 0, 867, 868, 3, 182, 91, 0, 868, 869,\n\t\t5, 2, 0, 0, 869, 871, 1, 0, 0, 0, 870, 867, 1, 0, 0, 0, 870, 871, 1, 0,\n\t\t0, 0, 871, 872, 1, 0, 0, 0, 872, 873, 3, 224, 112, 0, 873, 63, 1, 0, 0,\n\t\t0, 874, 875, 6, 32, -1, 0, 875, 963, 3, 68, 34, 0, 876, 963, 5, 187, 0,\n\t\t0, 877, 878, 3, 182, 91, 0, 878, 879, 5, 2, 0, 0, 879, 881, 1, 0, 0, 0,\n\t\t880, 877, 1, 0, 0, 0, 880, 881, 1, 0, 0, 0, 881, 882, 1, 0, 0, 0, 882,\n\t\t883, 3, 184, 92, 0, 883, 884, 5, 2, 0, 0, 884, 886, 1, 0, 0, 0, 885, 880,\n\t\t1, 0, 0, 0, 885, 886, 1, 0, 0, 0, 886, 887, 1, 0, 0, 0, 887, 963, 3, 188,\n\t\t94, 0, 888, 889, 3, 168, 84, 0, 889, 890, 3, 64, 32, 21, 890, 963, 1, 0,\n\t\t0, 0, 891, 892, 3, 180, 90, 0, 892, 905, 5, 3, 0, 0, 893, 895, 5, 62, 0,\n\t\t0, 894, 893, 1, 0, 0, 0, 894, 895, 1, 0, 0, 0, 895, 896, 1, 0, 0, 0, 896,\n\t\t901, 3, 64, 32, 0, 897, 898, 5, 5, 0, 0, 898, 900, 3, 64, 32, 0, 899, 897,\n\t\t1, 0, 0, 0, 900, 903, 1, 0, 0, 0, 901, 899, 1, 0, 0, 0, 901, 902, 1, 0,\n\t\t0, 0, 902, 906, 1, 0, 0, 0, 903, 901, 1, 0, 0, 0, 904, 906, 5, 7, 0, 0,\n\t\t905, 894, 1, 0, 0, 0, 905, 904, 1, 0, 0, 0, 905, 906, 1, 0, 0, 0, 906,\n\t\t907, 1, 0, 0, 0, 907, 909, 5, 4, 0, 0, 908, 910, 3, 118, 59, 0, 909, 908,\n\t\t1, 0, 0, 0, 909, 910, 1, 0, 0, 0, 910, 912, 1, 0, 0, 0, 911, 913, 3, 122,\n\t\t61, 0, 912, 911, 1, 0, 0, 0, 912, 913, 1, 0, 0, 0, 913, 963, 1, 0, 0, 0,\n\t\t914, 915, 5, 3, 0, 0, 915, 920, 3, 64, 32, 0, 916, 917, 5, 5, 0, 0, 917,\n\t\t919, 3, 64, 32, 0, 918, 916, 1, 0, 0, 0, 919, 922, 1, 0, 0, 0, 920, 918,\n\t\t1, 0, 0, 0, 920, 921, 1, 0, 0, 0, 921, 923, 1, 0, 0, 0, 922, 920, 1, 0,\n\t\t0, 0, 923, 924, 5, 4, 0, 0, 924, 963, 1, 0, 0, 0, 925, 926, 5, 43, 0, 0,\n\t\t926, 927, 5, 3, 0, 0, 927, 928, 3, 64, 32, 0, 928, 929, 5, 33, 0, 0, 929,\n\t\t930, 3, 30, 15, 0, 930, 931, 5, 4, 0, 0, 931, 963, 1, 0, 0, 0, 932, 934,\n\t\t5, 102, 0, 0, 933, 932, 1, 0, 0, 0, 933, 934, 1, 0, 0, 0, 934, 935, 1,\n\t\t0, 0, 0, 935, 937, 5, 70, 0, 0, 936, 933, 1, 0, 0, 0, 936, 937, 1, 0, 0,\n\t\t0, 937, 938, 1, 0, 0, 0, 938, 939, 5, 3, 0, 0, 939, 940, 3, 82, 41, 0,\n\t\t940, 941, 5, 4, 0, 0, 941, 963, 1, 0, 0, 0, 942, 944, 5, 42, 0, 0, 943,\n\t\t945, 3, 64, 32, 0, 944, 943, 1, 0, 0, 0, 944, 945, 1, 0, 0, 0, 945, 951,\n\t\t1, 0, 0, 0, 946, 947, 5, 147, 0, 0, 947, 948, 3, 64, 32, 0, 948, 949, 5,\n\t\t135, 0, 0, 949, 950, 3, 64, 32, 0, 950, 952, 1, 0, 0, 0, 951, 946, 1, 0,\n\t\t0, 0, 952, 953, 1, 0, 0, 0, 953, 951, 1, 0, 0, 0, 953, 954, 1, 0, 0, 0,\n\t\t954, 957, 1, 0, 0, 0, 955, 956, 5, 65, 0, 0, 956, 958, 3, 64, 32, 0, 957,\n\t\t955, 1, 0, 0, 0, 957, 958, 1, 0, 0, 0, 958, 959, 1, 0, 0, 0, 959, 960,\n\t\t5, 66, 0, 0, 960, 963, 1, 0, 0, 0, 961, 963, 3, 66, 33, 0, 962, 874, 1,\n\t\t0, 0, 0, 962, 876, 1, 0, 0, 0, 962, 885, 1, 0, 0, 0, 962, 888, 1, 0, 0,\n\t\t0, 962, 891, 1, 0, 0, 0, 962, 914, 1, 0, 0, 0, 962, 925, 1, 0, 0, 0, 962,\n\t\t936, 1, 0, 0, 0, 962, 942, 1, 0, 0, 0, 962, 961, 1, 0, 0, 0, 963, 1083,\n\t\t1, 0, 0, 0, 964, 965, 10, 20, 0, 0, 965, 966, 5, 11, 0, 0, 966, 1082, 3,\n\t\t64, 32, 21, 967, 968, 10, 19, 0, 0, 968, 969, 7, 10, 0, 0, 969, 1082, 3,\n\t\t64, 32, 20, 970, 971, 10, 18, 0, 0, 971, 972, 7, 4, 0, 0, 972, 1082, 3,\n\t\t64, 32, 19, 973, 974, 10, 17, 0, 0, 974, 975, 7, 11, 0, 0, 975, 1082, 3,\n\t\t64, 32, 18, 976, 977, 10, 16, 0, 0, 977, 978, 7, 12, 0, 0, 978, 1082, 3,\n\t\t64, 32, 17, 979, 992, 10, 15, 0, 0, 980, 993, 5, 6, 0, 0, 981, 993, 5,\n\t\t22, 0, 0, 982, 993, 5, 23, 0, 0, 983, 993, 5, 24, 0, 0, 984, 993, 5, 92,\n\t\t0, 0, 985, 986, 5, 92, 0, 0, 986, 993, 5, 102, 0, 0, 987, 993, 5, 83, 0,\n\t\t0, 988, 993, 5, 97, 0, 0, 989, 993, 5, 77, 0, 0, 990, 993, 5, 99, 0, 0,\n\t\t991, 993, 5, 118, 0, 0, 992, 980, 1, 0, 0, 0, 992, 981, 1, 0, 0, 0, 992,\n\t\t982, 1, 0, 0, 0, 992, 983, 1, 0, 0, 0, 992, 984, 1, 0, 0, 0, 992, 985,\n\t\t1, 0, 0, 0, 992, 987, 1, 0, 0, 0, 992, 988, 1, 0, 0, 0, 992, 989, 1, 0,\n\t\t0, 0, 992, 990, 1, 0, 0, 0, 992, 991, 1, 0, 0, 0, 993, 994, 1, 0, 0, 0,\n\t\t994, 1082, 3, 64, 32, 16, 995, 996, 10, 14, 0, 0, 996, 997, 5, 32, 0, 0,\n\t\t997, 1082, 3, 64, 32, 15, 998, 999, 10, 13, 0, 0, 999, 1000, 5, 108, 0,\n\t\t0, 1000, 1082, 3, 64, 32, 14, 1001, 1002, 10, 6, 0, 0, 1002, 1004, 5, 92,\n\t\t0, 0, 1003, 1005, 5, 102, 0, 0, 1004, 1003, 1, 0, 0, 0, 1004, 1005, 1,\n\t\t0, 0, 0, 1005, 1006, 1, 0, 0, 0, 1006, 1082, 3, 64, 32, 7, 1007, 1009,\n\t\t10, 5, 0, 0, 1008, 1010, 5, 102, 0, 0, 1009, 1008, 1, 0, 0, 0, 1009, 1010,\n\t\t1, 0, 0, 0, 1010, 1011, 1, 0, 0, 0, 1011, 1012, 5, 39, 0, 0, 1012, 1013,\n\t\t3, 64, 32, 0, 1013, 1014, 5, 32, 0, 0, 1014, 1015, 3, 64, 32, 6, 1015,\n\t\t1082, 1, 0, 0, 0, 1016, 1017, 10, 9, 0, 0, 1017, 1018, 5, 45, 0, 0, 1018,\n\t\t1082, 3, 190, 95, 0, 1019, 1021, 10, 8, 0, 0, 1020, 1022, 5, 102, 0, 0,\n\t\t1021, 1020, 1, 0, 0, 0, 1021, 1022, 1, 0, 0, 0, 1022, 1023, 1, 0, 0, 0,\n\t\t1023, 1024, 7, 13, 0, 0, 1024, 1027, 3, 64, 32, 0, 1025, 1026, 5, 67, 0,\n\t\t0, 1026, 1028, 3, 64, 32, 0, 1027, 1025, 1, 0, 0, 0, 1027, 1028, 1, 0,\n\t\t0, 0, 1028, 1082, 1, 0, 0, 0, 1029, 1034, 10, 7, 0, 0, 1030, 1035, 5, 93,\n\t\t0, 0, 1031, 1035, 5, 103, 0, 0, 1032, 1033, 5, 102, 0, 0, 1033, 1035, 5,\n\t\t104, 0, 0, 1034, 1030, 1, 0, 0, 0, 1034, 1031, 1, 0, 0, 0, 1034, 1032,\n\t\t1, 0, 0, 0, 1035, 1082, 1, 0, 0, 0, 1036, 1038, 10, 4, 0, 0, 1037, 1039,\n\t\t5, 102, 0, 0, 1038, 1037, 1, 0, 0, 0, 1038, 1039, 1, 0, 0, 0, 1039, 1040,\n\t\t1, 0, 0, 0, 1040, 1079, 5, 83, 0, 0, 1041, 1051, 5, 3, 0, 0, 1042, 1052,\n\t\t3, 82, 41, 0, 1043, 1048, 3, 64, 32, 0, 1044, 1045, 5, 5, 0, 0, 1045, 1047,\n\t\t3, 64, 32, 0, 1046, 1044, 1, 0, 0, 0, 1047, 1050, 1, 0, 0, 0, 1048, 1046,\n\t\t1, 0, 0, 0, 1048, 1049, 1, 0, 0, 0, 1049, 1052, 1, 0, 0, 0, 1050, 1048,\n\t\t1, 0, 0, 0, 1051, 1042, 1, 0, 0, 0, 1051, 1043, 1, 0, 0, 0, 1051, 1052,\n\t\t1, 0, 0, 0, 1052, 1053, 1, 0, 0, 0, 1053, 1080, 5, 4, 0, 0, 1054, 1055,\n\t\t3, 182, 91, 0, 1055, 1056, 5, 2, 0, 0, 1056, 1058, 1, 0, 0, 0, 1057, 1054,\n\t\t1, 0, 0, 0, 1057, 1058, 1, 0, 0, 0, 1058, 1059, 1, 0, 0, 0, 1059, 1080,\n\t\t3, 184, 92, 0, 1060, 1061, 3, 182, 91, 0, 1061, 1062, 5, 2, 0, 0, 1062,\n\t\t1064, 1, 0, 0, 0, 1063, 1060, 1, 0, 0, 0, 1063, 1064, 1, 0, 0, 0, 1064,\n\t\t1065, 1, 0, 0, 0, 1065, 1066, 3, 222, 111, 0, 1066, 1075, 5, 3, 0, 0, 1067,\n\t\t1072, 3, 64, 32, 0, 1068, 1069, 5, 5, 0, 0, 1069, 1071, 3, 64, 32, 0, 1070,\n\t\t1068, 1, 0, 0, 0, 1071, 1074, 1, 0, 0, 0, 1072, 1070, 1, 0, 0, 0, 1072,\n\t\t1073, 1, 0, 0, 0, 1073, 1076, 1, 0, 0, 0, 1074, 1072, 1, 0, 0, 0, 1075,\n\t\t1067, 1, 0, 0, 0, 1075, 1076, 1, 0, 0, 0, 1076, 1077, 1, 0, 0, 0, 1077,\n\t\t1078, 5, 4, 0, 0, 1078, 1080, 1, 0, 0, 0, 1079, 1041, 1, 0, 0, 0, 1079,\n\t\t1057, 1, 0, 0, 0, 1079, 1063, 1, 0, 0, 0, 1080, 1082, 1, 0, 0, 0, 1081,\n\t\t964, 1, 0, 0, 0, 1081, 967, 1, 0, 0, 0, 1081, 970, 1, 0, 0, 0, 1081, 973,\n\t\t1, 0, 0, 0, 1081, 976, 1, 0, 0, 0, 1081, 979, 1, 0, 0, 0, 1081, 995, 1,\n\t\t0, 0, 0, 1081, 998, 1, 0, 0, 0, 1081, 1001, 1, 0, 0, 0, 1081, 1007, 1,\n\t\t0, 0, 0, 1081, 1016, 1, 0, 0, 0, 1081, 1019, 1, 0, 0, 0, 1081, 1029, 1,\n\t\t0, 0, 0, 1081, 1036, 1, 0, 0, 0, 1082, 1085, 1, 0, 0, 0, 1083, 1081, 1,\n\t\t0, 0, 0, 1083, 1084, 1, 0, 0, 0, 1084, 65, 1, 0, 0, 0, 1085, 1083, 1, 0,\n\t\t0, 0, 1086, 1087, 5, 115, 0, 0, 1087, 1092, 5, 3, 0, 0, 1088, 1093, 5,\n\t\t81, 0, 0, 1089, 1090, 7, 14, 0, 0, 1090, 1091, 5, 5, 0, 0, 1091, 1093,\n\t\t3, 170, 85, 0, 1092, 1088, 1, 0, 0, 0, 1092, 1089, 1, 0, 0, 0, 1093, 1094,\n\t\t1, 0, 0, 0, 1094, 1095, 5, 4, 0, 0, 1095, 67, 1, 0, 0, 0, 1096, 1097, 7,\n\t\t15, 0, 0, 1097, 69, 1, 0, 0, 0, 1098, 1100, 3, 48, 24, 0, 1099, 1098, 1,\n\t\t0, 0, 0, 1099, 1100, 1, 0, 0, 0, 1100, 1106, 1, 0, 0, 0, 1101, 1107, 5,\n\t\t88, 0, 0, 1102, 1107, 5, 122, 0, 0, 1103, 1104, 5, 88, 0, 0, 1104, 1105,\n\t\t5, 108, 0, 0, 1105, 1107, 7, 8, 0, 0, 1106, 1101, 1, 0, 0, 0, 1106, 1102,\n\t\t1, 0, 0, 0, 1106, 1103, 1, 0, 0, 0, 1107, 1108, 1, 0, 0, 0, 1108, 1112,\n\t\t5, 91, 0, 0, 1109, 1110, 3, 182, 91, 0, 1110, 1111, 5, 2, 0, 0, 1111, 1113,\n\t\t1, 0, 0, 0, 1112, 1109, 1, 0, 0, 0, 1112, 1113, 1, 0, 0, 0, 1113, 1114,\n\t\t1, 0, 0, 0, 1114, 1117, 3, 184, 92, 0, 1115, 1116, 5, 33, 0, 0, 1116, 1118,\n\t\t3, 206, 103, 0, 1117, 1115, 1, 0, 0, 0, 1117, 1118, 1, 0, 0, 0, 1118, 1130,\n\t\t1, 0, 0, 0, 1119, 1120, 5, 3, 0, 0, 1120, 1125, 3, 188, 94, 0, 1121, 1122,\n\t\t5, 5, 0, 0, 1122, 1124, 3, 188, 94, 0, 1123, 1121, 1, 0, 0, 0, 1124, 1127,\n\t\t1, 0, 0, 0, 1125, 1123, 1, 0, 0, 0, 1125, 1126, 1, 0, 0, 0, 1126, 1128,\n\t\t1, 0, 0, 0, 1127, 1125, 1, 0, 0, 0, 1128, 1129, 5, 4, 0, 0, 1129, 1131,\n\t\t1, 0, 0, 0, 1130, 1119, 1, 0, 0, 0, 1130, 1131, 1, 0, 0, 0, 1131, 1168,\n\t\t1, 0, 0, 0, 1132, 1133, 5, 144, 0, 0, 1133, 1134, 5, 3, 0, 0, 1134, 1139,\n\t\t3, 64, 32, 0, 1135, 1136, 5, 5, 0, 0, 1136, 1138, 3, 64, 32, 0, 1137, 1135,\n\t\t1, 0, 0, 0, 1138, 1141, 1, 0, 0, 0, 1139, 1137, 1, 0, 0, 0, 1139, 1140,\n\t\t1, 0, 0, 0, 1140, 1142, 1, 0, 0, 0, 1141, 1139, 1, 0, 0, 0, 1142, 1157,\n\t\t5, 4, 0, 0, 1143, 1144, 5, 5, 0, 0, 1144, 1145, 5, 3, 0, 0, 1145, 1150,\n\t\t3, 64, 32, 0, 1146, 1147, 5, 5, 0, 0, 1147, 1149, 3, 64, 32, 0, 1148, 1146,\n\t\t1, 0, 0, 0, 1149, 1152, 1, 0, 0, 0, 1150, 1148, 1, 0, 0, 0, 1150, 1151,\n\t\t1, 0, 0, 0, 1151, 1153, 1, 0, 0, 0, 1152, 1150, 1, 0, 0, 0, 1153, 1154,\n\t\t5, 4, 0, 0, 1154, 1156, 1, 0, 0, 0, 1155, 1143, 1, 0, 0, 0, 1156, 1159,\n\t\t1, 0, 0, 0, 1157, 1155, 1, 0, 0, 0, 1157, 1158, 1, 0, 0, 0, 1158, 1162,\n\t\t1, 0, 0, 0, 1159, 1157, 1, 0, 0, 0, 1160, 1162, 3, 82, 41, 0, 1161, 1132,\n\t\t1, 0, 0, 0, 1161, 1160, 1, 0, 0, 0, 1162, 1164, 1, 0, 0, 0, 1163, 1165,\n\t\t3, 74, 37, 0, 1164, 1163, 1, 0, 0, 0, 1164, 1165, 1, 0, 0, 0, 1165, 1169,\n\t\t1, 0, 0, 0, 1166, 1167, 5, 56, 0, 0, 1167, 1169, 5, 144, 0, 0, 1168, 1161,\n\t\t1, 0, 0, 0, 1168, 1166, 1, 0, 0, 0, 1169, 1171, 1, 0, 0, 0, 1170, 1172,\n\t\t3, 72, 36, 0, 1171, 1170, 1, 0, 0, 0, 1171, 1172, 1, 0, 0, 0, 1172, 71,\n\t\t1, 0, 0, 0, 1173, 1174, 5, 124, 0, 0, 1174, 1179, 3, 96, 48, 0, 1175, 1176,\n\t\t5, 5, 0, 0, 1176, 1178, 3, 96, 48, 0, 1177, 1175, 1, 0, 0, 0, 1178, 1181,\n\t\t1, 0, 0, 0, 1179, 1177, 1, 0, 0, 0, 1179, 1180, 1, 0, 0, 0, 1180, 73, 1,\n\t\t0, 0, 0, 1181, 1179, 1, 0, 0, 0, 1182, 1183, 5, 107, 0, 0, 1183, 1198,\n\t\t5, 48, 0, 0, 1184, 1185, 5, 3, 0, 0, 1185, 1190, 3, 24, 12, 0, 1186, 1187,\n\t\t5, 5, 0, 0, 1187, 1189, 3, 24, 12, 0, 1188, 1186, 1, 0, 0, 0, 1189, 1192,\n\t\t1, 0, 0, 0, 1190, 1188, 1, 0, 0, 0, 1190, 1191, 1, 0, 0, 0, 1191, 1193,\n\t\t1, 0, 0, 0, 1192, 1190, 1, 0, 0, 0, 1193, 1196, 5, 4, 0, 0, 1194, 1195,\n\t\t5, 148, 0, 0, 1195, 1197, 3, 64, 32, 0, 1196, 1194, 1, 0, 0, 0, 1196, 1197,\n\t\t1, 0, 0, 0, 1197, 1199, 1, 0, 0, 0, 1198, 1184, 1, 0, 0, 0, 1198, 1199,\n\t\t1, 0, 0, 0, 1199, 1200, 1, 0, 0, 0, 1200, 1227, 5, 183, 0, 0, 1201, 1228,\n\t\t5, 184, 0, 0, 1202, 1203, 5, 141, 0, 0, 1203, 1206, 5, 131, 0, 0, 1204,\n\t\t1207, 3, 188, 94, 0, 1205, 1207, 3, 110, 55, 0, 1206, 1204, 1, 0, 0, 0,\n\t\t1206, 1205, 1, 0, 0, 0, 1207, 1208, 1, 0, 0, 0, 1208, 1209, 5, 6, 0, 0,\n\t\t1209, 1220, 3, 64, 32, 0, 1210, 1213, 5, 5, 0, 0, 1211, 1214, 3, 188, 94,\n\t\t0, 1212, 1214, 3, 110, 55, 0, 1213, 1211, 1, 0, 0, 0, 1213, 1212, 1, 0,\n\t\t0, 0, 1214, 1215, 1, 0, 0, 0, 1215, 1216, 5, 6, 0, 0, 1216, 1217, 3, 64,\n\t\t32, 0, 1217, 1219, 1, 0, 0, 0, 1218, 1210, 1, 0, 0, 0, 1219, 1222, 1, 0,\n\t\t0, 0, 1220, 1218, 1, 0, 0, 0, 1220, 1221, 1, 0, 0, 0, 1221, 1225, 1, 0,\n\t\t0, 0, 1222, 1220, 1, 0, 0, 0, 1223, 1224, 5, 148, 0, 0, 1224, 1226, 3,\n\t\t64, 32, 0, 1225, 1223, 1, 0, 0, 0, 1225, 1226, 1, 0, 0, 0, 1226, 1228,\n\t\t1, 0, 0, 0, 1227, 1201, 1, 0, 0, 0, 1227, 1202, 1, 0, 0, 0, 1228, 75, 1,\n\t\t0, 0, 0, 1229, 1233, 5, 112, 0, 0, 1230, 1231, 3, 182, 91, 0, 1231, 1232,\n\t\t5, 2, 0, 0, 1232, 1234, 1, 0, 0, 0, 1233, 1230, 1, 0, 0, 0, 1233, 1234,\n\t\t1, 0, 0, 0, 1234, 1235, 1, 0, 0, 0, 1235, 1242, 3, 202, 101, 0, 1236, 1237,\n\t\t5, 6, 0, 0, 1237, 1243, 3, 78, 39, 0, 1238, 1239, 5, 3, 0, 0, 1239, 1240,\n\t\t3, 78, 39, 0, 1240, 1241, 5, 4, 0, 0, 1241, 1243, 1, 0, 0, 0, 1242, 1236,\n\t\t1, 0, 0, 0, 1242, 1238, 1, 0, 0, 0, 1242, 1243, 1, 0, 0, 0, 1243, 77, 1,\n\t\t0, 0, 0, 1244, 1248, 3, 34, 17, 0, 1245, 1248, 3, 178, 89, 0, 1246, 1248,\n\t\t5, 188, 0, 0, 1247, 1244, 1, 0, 0, 0, 1247, 1245, 1, 0, 0, 0, 1247, 1246,\n\t\t1, 0, 0, 0, 1248, 79, 1, 0, 0, 0, 1249, 1260, 5, 119, 0, 0, 1250, 1261,\n\t\t3, 190, 95, 0, 1251, 1252, 3, 182, 91, 0, 1252, 1253, 5, 2, 0, 0, 1253,\n\t\t1255, 1, 0, 0, 0, 1254, 1251, 1, 0, 0, 0, 1254, 1255, 1, 0, 0, 0, 1255,\n\t\t1258, 1, 0, 0, 0, 1256, 1259, 3, 184, 92, 0, 1257, 1259, 3, 194, 97, 0,\n\t\t1258, 1256, 1, 0, 0, 0, 1258, 1257, 1, 0, 0, 0, 1259, 1261, 1, 0, 0, 0,\n\t\t1260, 1250, 1, 0, 0, 0, 1260, 1254, 1, 0, 0, 0, 1260, 1261, 1, 0, 0, 0,\n\t\t1261, 81, 1, 0, 0, 0, 1262, 1264, 3, 134, 67, 0, 1263, 1262, 1, 0, 0, 0,\n\t\t1263, 1264, 1, 0, 0, 0, 1264, 1265, 1, 0, 0, 0, 1265, 1271, 3, 86, 43,\n\t\t0, 1266, 1267, 3, 102, 51, 0, 1267, 1268, 3, 86, 43, 0, 1268, 1270, 1,\n\t\t0, 0, 0, 1269, 1266, 1, 0, 0, 0, 1270, 1273, 1, 0, 0, 0, 1271, 1269, 1,\n\t\t0, 0, 0, 1271, 1272, 1, 0, 0, 0, 1272, 1275, 1, 0, 0, 0, 1273, 1271, 1,\n\t\t0, 0, 0, 1274, 1276, 3, 136, 68, 0, 1275, 1274, 1, 0, 0, 0, 1275, 1276,\n\t\t1, 0, 0, 0, 1276, 1278, 1, 0, 0, 0, 1277, 1279, 3, 138, 69, 0, 1278, 1277,\n\t\t1, 0, 0, 0, 1278, 1279, 1, 0, 0, 0, 1279, 83, 1, 0, 0, 0, 1280, 1288, 3,\n\t\t94, 47, 0, 1281, 1282, 3, 98, 49, 0, 1282, 1284, 3, 94, 47, 0, 1283, 1285,\n\t\t3, 100, 50, 0, 1284, 1283, 1, 0, 0, 0, 1284, 1285, 1, 0, 0, 0, 1285, 1287,\n\t\t1, 0, 0, 0, 1286, 1281, 1, 0, 0, 0, 1287, 1290, 1, 0, 0, 0, 1288, 1286,\n\t\t1, 0, 0, 0, 1288, 1289, 1, 0, 0, 0, 1289, 85, 1, 0, 0, 0, 1290, 1288, 1,\n\t\t0, 0, 0, 1291, 1293, 5, 130, 0, 0, 1292, 1294, 7, 16, 0, 0, 1293, 1292,\n\t\t1, 0, 0, 0, 1293, 1294, 1, 0, 0, 0, 1294, 1295, 1, 0, 0, 0, 1295, 1300,\n\t\t3, 96, 48, 0, 1296, 1297, 5, 5, 0, 0, 1297, 1299, 3, 96, 48, 0, 1298, 1296,\n\t\t1, 0, 0, 0, 1299, 1302, 1, 0, 0, 0, 1300, 1298, 1, 0, 0, 0, 1300, 1301,\n\t\t1, 0, 0, 0, 1301, 1315, 1, 0, 0, 0, 1302, 1300, 1, 0, 0, 0, 1303, 1313,\n\t\t5, 75, 0, 0, 1304, 1309, 3, 94, 47, 0, 1305, 1306, 5, 5, 0, 0, 1306, 1308,\n\t\t3, 94, 47, 0, 1307, 1305, 1, 0, 0, 0, 1308, 1311, 1, 0, 0, 0, 1309, 1307,\n\t\t1, 0, 0, 0, 1309, 1310, 1, 0, 0, 0, 1310, 1314, 1, 0, 0, 0, 1311, 1309,\n\t\t1, 0, 0, 0, 1312, 1314, 3, 84, 42, 0, 1313, 1304, 1, 0, 0, 0, 1313, 1312,\n\t\t1, 0, 0, 0, 1314, 1316, 1, 0, 0, 0, 1315, 1303, 1, 0, 0, 0, 1315, 1316,\n\t\t1, 0, 0, 0, 1316, 1319, 1, 0, 0, 0, 1317, 1318, 5, 148, 0, 0, 1318, 1320,\n\t\t3, 64, 32, 0, 1319, 1317, 1, 0, 0, 0, 1319, 1320, 1, 0, 0, 0, 1320, 1335,\n\t\t1, 0, 0, 0, 1321, 1322, 5, 78, 0, 0, 1322, 1323, 5, 40, 0, 0, 1323, 1328,\n\t\t3, 64, 32, 0, 1324, 1325, 5, 5, 0, 0, 1325, 1327, 3, 64, 32, 0, 1326, 1324,\n\t\t1, 0, 0, 0, 1327, 1330, 1, 0, 0, 0, 1328, 1326, 1, 0, 0, 0, 1328, 1329,\n\t\t1, 0, 0, 0, 1329, 1333, 1, 0, 0, 0, 1330, 1328, 1, 0, 0, 0, 1331, 1332,\n\t\t5, 79, 0, 0, 1332, 1334, 3, 64, 32, 0, 1333, 1331, 1, 0, 0, 0, 1333, 1334,\n\t\t1, 0, 0, 0, 1334, 1336, 1, 0, 0, 0, 1335, 1321, 1, 0, 0, 0, 1335, 1336,\n\t\t1, 0, 0, 0, 1336, 1351, 1, 0, 0, 0, 1337, 1338, 5, 174, 0, 0, 1338, 1339,\n\t\t3, 210, 105, 0, 1339, 1340, 5, 33, 0, 0, 1340, 1348, 3, 120, 60, 0, 1341,\n\t\t1342, 5, 5, 0, 0, 1342, 1343, 3, 210, 105, 0, 1343, 1344, 5, 33, 0, 0,\n\t\t1344, 1345, 3, 120, 60, 0, 1345, 1347, 1, 0, 0, 0, 1346, 1341, 1, 0, 0,\n\t\t0, 1347, 1350, 1, 0, 0, 0, 1348, 1346, 1, 0, 0, 0, 1348, 1349, 1, 0, 0,\n\t\t0, 1349, 1352, 1, 0, 0, 0, 1350, 1348, 1, 0, 0, 0, 1351, 1337, 1, 0, 0,\n\t\t0, 1351, 1352, 1, 0, 0, 0, 1352, 1382, 1, 0, 0, 0, 1353, 1354, 5, 144,\n\t\t0, 0, 1354, 1355, 5, 3, 0, 0, 1355, 1360, 3, 64, 32, 0, 1356, 1357, 5,\n\t\t5, 0, 0, 1357, 1359, 3, 64, 32, 0, 1358, 1356, 1, 0, 0, 0, 1359, 1362,\n\t\t1, 0, 0, 0, 1360, 1358, 1, 0, 0, 0, 1360, 1361, 1, 0, 0, 0, 1361, 1363,\n\t\t1, 0, 0, 0, 1362, 1360, 1, 0, 0, 0, 1363, 1378, 5, 4, 0, 0, 1364, 1365,\n\t\t5, 5, 0, 0, 1365, 1366, 5, 3, 0, 0, 1366, 1371, 3, 64, 32, 0, 1367, 1368,\n\t\t5, 5, 0, 0, 1368, 1370, 3, 64, 32, 0, 1369, 1367, 1, 0, 0, 0, 1370, 1373,\n\t\t1, 0, 0, 0, 1371, 1369, 1, 0, 0, 0, 1371, 1372, 1, 0, 0, 0, 1372, 1374,\n\t\t1, 0, 0, 0, 1373, 1371, 1, 0, 0, 0, 1374, 1375, 5, 4, 0, 0, 1375, 1377,\n\t\t1, 0, 0, 0, 1376, 1364, 1, 0, 0, 0, 1377, 1380, 1, 0, 0, 0, 1378, 1376,\n\t\t1, 0, 0, 0, 1378, 1379, 1, 0, 0, 0, 1379, 1382, 1, 0, 0, 0, 1380, 1378,\n\t\t1, 0, 0, 0, 1381, 1291, 1, 0, 0, 0, 1381, 1353, 1, 0, 0, 0, 1382, 87, 1,\n\t\t0, 0, 0, 1383, 1384, 3, 82, 41, 0, 1384, 89, 1, 0, 0, 0, 1385, 1387, 3,\n\t\t134, 67, 0, 1386, 1385, 1, 0, 0, 0, 1386, 1387, 1, 0, 0, 0, 1387, 1388,\n\t\t1, 0, 0, 0, 1388, 1390, 3, 86, 43, 0, 1389, 1391, 3, 136, 68, 0, 1390,\n\t\t1389, 1, 0, 0, 0, 1390, 1391, 1, 0, 0, 0, 1391, 1393, 1, 0, 0, 0, 1392,\n\t\t1394, 3, 138, 69, 0, 1393, 1392, 1, 0, 0, 0, 1393, 1394, 1, 0, 0, 0, 1394,\n\t\t91, 1, 0, 0, 0, 1395, 1397, 3, 134, 67, 0, 1396, 1395, 1, 0, 0, 0, 1396,\n\t\t1397, 1, 0, 0, 0, 1397, 1398, 1, 0, 0, 0, 1398, 1408, 3, 86, 43, 0, 1399,\n\t\t1401, 5, 139, 0, 0, 1400, 1402, 5, 29, 0, 0, 1401, 1400, 1, 0, 0, 0, 1401,\n\t\t1402, 1, 0, 0, 0, 1402, 1406, 1, 0, 0, 0, 1403, 1406, 5, 90, 0, 0, 1404,\n\t\t1406, 5, 68, 0, 0, 1405, 1399, 1, 0, 0, 0, 1405, 1403, 1, 0, 0, 0, 1405,\n\t\t1404, 1, 0, 0, 0, 1406, 1407, 1, 0, 0, 0, 1407, 1409, 3, 86, 43, 0, 1408,\n\t\t1405, 1, 0, 0, 0, 1409, 1410, 1, 0, 0, 0, 1410, 1408, 1, 0, 0, 0, 1410,\n\t\t1411, 1, 0, 0, 0, 1411, 1413, 1, 0, 0, 0, 1412, 1414, 3, 136, 68, 0, 1413,\n\t\t1412, 1, 0, 0, 0, 1413, 1414, 1, 0, 0, 0, 1414, 1416, 1, 0, 0, 0, 1415,\n\t\t1417, 3, 138, 69, 0, 1416, 1415, 1, 0, 0, 0, 1416, 1417, 1, 0, 0, 0, 1417,\n\t\t93, 1, 0, 0, 0, 1418, 1419, 3, 182, 91, 0, 1419, 1420, 5, 2, 0, 0, 1420,\n\t\t1422, 1, 0, 0, 0, 1421, 1418, 1, 0, 0, 0, 1421, 1422, 1, 0, 0, 0, 1422,\n\t\t1423, 1, 0, 0, 0, 1423, 1428, 3, 184, 92, 0, 1424, 1426, 5, 33, 0, 0, 1425,\n\t\t1424, 1, 0, 0, 0, 1425, 1426, 1, 0, 0, 0, 1426, 1427, 1, 0, 0, 0, 1427,\n\t\t1429, 3, 206, 103, 0, 1428, 1425, 1, 0, 0, 0, 1428, 1429, 1, 0, 0, 0, 1429,\n\t\t1435, 1, 0, 0, 0, 1430, 1431, 5, 85, 0, 0, 1431, 1432, 5, 40, 0, 0, 1432,\n\t\t1436, 3, 194, 97, 0, 1433, 1434, 5, 102, 0, 0, 1434, 1436, 5, 85, 0, 0,\n\t\t1435, 1430, 1, 0, 0, 0, 1435, 1433, 1, 0, 0, 0, 1435, 1436, 1, 0, 0, 0,\n\t\t1436, 1483, 1, 0, 0, 0, 1437, 1438, 3, 182, 91, 0, 1438, 1439, 5, 2, 0,\n\t\t0, 1439, 1441, 1, 0, 0, 0, 1440, 1437, 1, 0, 0, 0, 1440, 1441, 1, 0, 0,\n\t\t0, 1441, 1442, 1, 0, 0, 0, 1442, 1443, 3, 222, 111, 0, 1443, 1444, 5, 3,\n\t\t0, 0, 1444, 1449, 3, 64, 32, 0, 1445, 1446, 5, 5, 0, 0, 1446, 1448, 3,\n\t\t64, 32, 0, 1447, 1445, 1, 0, 0, 0, 1448, 1451, 1, 0, 0, 0, 1449, 1447,\n\t\t1, 0, 0, 0, 1449, 1450, 1, 0, 0, 0, 1450, 1452, 1, 0, 0, 0, 1451, 1449,\n\t\t1, 0, 0, 0, 1452, 1457, 5, 4, 0, 0, 1453, 1455, 5, 33, 0, 0, 1454, 1453,\n\t\t1, 0, 0, 0, 1454, 1455, 1, 0, 0, 0, 1455, 1456, 1, 0, 0, 0, 1456, 1458,\n\t\t3, 206, 103, 0, 1457, 1454, 1, 0, 0, 0, 1457, 1458, 1, 0, 0, 0, 1458, 1483,\n\t\t1, 0, 0, 0, 1459, 1469, 5, 3, 0, 0, 1460, 1465, 3, 94, 47, 0, 1461, 1462,\n\t\t5, 5, 0, 0, 1462, 1464, 3, 94, 47, 0, 1463, 1461, 1, 0, 0, 0, 1464, 1467,\n\t\t1, 0, 0, 0, 1465, 1463, 1, 0, 0, 0, 1465, 1466, 1, 0, 0, 0, 1466, 1470,\n\t\t1, 0, 0, 0, 1467, 1465, 1, 0, 0, 0, 1468, 1470, 3, 84, 42, 0, 1469, 1460,\n\t\t1, 0, 0, 0, 1469, 1468, 1, 0, 0, 0, 1470, 1471, 1, 0, 0, 0, 1471, 1472,\n\t\t5, 4, 0, 0, 1472, 1483, 1, 0, 0, 0, 1473, 1474, 5, 3, 0, 0, 1474, 1475,\n\t\t3, 82, 41, 0, 1475, 1480, 5, 4, 0, 0, 1476, 1478, 5, 33, 0, 0, 1477, 1476,\n\t\t1, 0, 0, 0, 1477, 1478, 1, 0, 0, 0, 1478, 1479, 1, 0, 0, 0, 1479, 1481,\n\t\t3, 206, 103, 0, 1480, 1477, 1, 0, 0, 0, 1480, 1481, 1, 0, 0, 0, 1481, 1483,\n\t\t1, 0, 0, 0, 1482, 1421, 1, 0, 0, 0, 1482, 1440, 1, 0, 0, 0, 1482, 1459,\n\t\t1, 0, 0, 0, 1482, 1473, 1, 0, 0, 0, 1483, 95, 1, 0, 0, 0, 1484, 1497, 5,\n\t\t7, 0, 0, 1485, 1486, 3, 184, 92, 0, 1486, 1487, 5, 2, 0, 0, 1487, 1488,\n\t\t5, 7, 0, 0, 1488, 1497, 1, 0, 0, 0, 1489, 1494, 3, 64, 32, 0, 1490, 1492,\n\t\t5, 33, 0, 0, 1491, 1490, 1, 0, 0, 0, 1491, 1492, 1, 0, 0, 0, 1492, 1493,\n\t\t1, 0, 0, 0, 1493, 1495, 3, 174, 87, 0, 1494, 1491, 1, 0, 0, 0, 1494, 1495,\n\t\t1, 0, 0, 0, 1495, 1497, 1, 0, 0, 0, 1496, 1484, 1, 0, 0, 0, 1496, 1485,\n\t\t1, 0, 0, 0, 1496, 1489, 1, 0, 0, 0, 1497, 97, 1, 0, 0, 0, 1498, 1512, 5,\n\t\t5, 0, 0, 1499, 1501, 5, 100, 0, 0, 1500, 1499, 1, 0, 0, 0, 1500, 1501,\n\t\t1, 0, 0, 0, 1501, 1508, 1, 0, 0, 0, 1502, 1504, 5, 96, 0, 0, 1503, 1505,\n\t\t5, 110, 0, 0, 1504, 1503, 1, 0, 0, 0, 1504, 1505, 1, 0, 0, 0, 1505, 1509,\n\t\t1, 0, 0, 0, 1506, 1509, 5, 87, 0, 0, 1507, 1509, 5, 51, 0, 0, 1508, 1502,\n\t\t1, 0, 0, 0, 1508, 1506, 1, 0, 0, 0, 1508, 1507, 1, 0, 0, 0, 1508, 1509,\n\t\t1, 0, 0, 0, 1509, 1510, 1, 0, 0, 0, 1510, 1512, 5, 94, 0, 0, 1511, 1498,\n\t\t1, 0, 0, 0, 1511, 1500, 1, 0, 0, 0, 1512, 99, 1, 0, 0, 0, 1513, 1514, 5,\n\t\t107, 0, 0, 1514, 1528, 3, 64, 32, 0, 1515, 1516, 5, 142, 0, 0, 1516, 1517,\n\t\t5, 3, 0, 0, 1517, 1522, 3, 188, 94, 0, 1518, 1519, 5, 5, 0, 0, 1519, 1521,\n\t\t3, 188, 94, 0, 1520, 1518, 1, 0, 0, 0, 1521, 1524, 1, 0, 0, 0, 1522, 1520,\n\t\t1, 0, 0, 0, 1522, 1523, 1, 0, 0, 0, 1523, 1525, 1, 0, 0, 0, 1524, 1522,\n\t\t1, 0, 0, 0, 1525, 1526, 5, 4, 0, 0, 1526, 1528, 1, 0, 0, 0, 1527, 1513,\n\t\t1, 0, 0, 0, 1527, 1515, 1, 0, 0, 0, 1528, 101, 1, 0, 0, 0, 1529, 1531,\n\t\t5, 139, 0, 0, 1530, 1532, 5, 29, 0, 0, 1531, 1530, 1, 0, 0, 0, 1531, 1532,\n\t\t1, 0, 0, 0, 1532, 1536, 1, 0, 0, 0, 1533, 1536, 5, 90, 0, 0, 1534, 1536,\n\t\t5, 68, 0, 0, 1535, 1529, 1, 0, 0, 0, 1535, 1533, 1, 0, 0, 0, 1535, 1534,\n\t\t1, 0, 0, 0, 1536, 103, 1, 0, 0, 0, 1537, 1539, 3, 48, 24, 0, 1538, 1537,\n\t\t1, 0, 0, 0, 1538, 1539, 1, 0, 0, 0, 1539, 1540, 1, 0, 0, 0, 1540, 1543,\n\t\t5, 141, 0, 0, 1541, 1542, 5, 108, 0, 0, 1542, 1544, 7, 8, 0, 0, 1543, 1541,\n\t\t1, 0, 0, 0, 1543, 1544, 1, 0, 0, 0, 1544, 1545, 1, 0, 0, 0, 1545, 1546,\n\t\t3, 114, 57, 0, 1546, 1547, 5, 131, 0, 0, 1547, 1560, 3, 106, 53, 0, 1548,\n\t\t1558, 5, 75, 0, 0, 1549, 1554, 3, 94, 47, 0, 1550, 1551, 5, 5, 0, 0, 1551,\n\t\t1553, 3, 94, 47, 0, 1552, 1550, 1, 0, 0, 0, 1553, 1556, 1, 0, 0, 0, 1554,\n\t\t1552, 1, 0, 0, 0, 1554, 1555, 1, 0, 0, 0, 1555, 1559, 1, 0, 0, 0, 1556,\n\t\t1554, 1, 0, 0, 0, 1557, 1559, 3, 84, 42, 0, 1558, 1549, 1, 0, 0, 0, 1558,\n\t\t1557, 1, 0, 0, 0, 1559, 1561, 1, 0, 0, 0, 1560, 1548, 1, 0, 0, 0, 1560,\n\t\t1561, 1, 0, 0, 0, 1561, 1564, 1, 0, 0, 0, 1562, 1563, 5, 148, 0, 0, 1563,\n\t\t1565, 3, 64, 32, 0, 1564, 1562, 1, 0, 0, 0, 1564, 1565, 1, 0, 0, 0, 1565,\n\t\t1567, 1, 0, 0, 0, 1566, 1568, 3, 72, 36, 0, 1567, 1566, 1, 0, 0, 0, 1567,\n\t\t1568, 1, 0, 0, 0, 1568, 105, 1, 0, 0, 0, 1569, 1574, 3, 108, 54, 0, 1570,\n\t\t1571, 5, 5, 0, 0, 1571, 1573, 3, 108, 54, 0, 1572, 1570, 1, 0, 0, 0, 1573,\n\t\t1576, 1, 0, 0, 0, 1574, 1572, 1, 0, 0, 0, 1574, 1575, 1, 0, 0, 0, 1575,\n\t\t107, 1, 0, 0, 0, 1576, 1574, 1, 0, 0, 0, 1577, 1580, 3, 188, 94, 0, 1578,\n\t\t1580, 3, 110, 55, 0, 1579, 1577, 1, 0, 0, 0, 1579, 1578, 1, 0, 0, 0, 1580,\n\t\t1581, 1, 0, 0, 0, 1581, 1582, 5, 6, 0, 0, 1582, 1583, 3, 64, 32, 0, 1583,\n\t\t109, 1, 0, 0, 0, 1584, 1585, 5, 3, 0, 0, 1585, 1590, 3, 188, 94, 0, 1586,\n\t\t1587, 5, 5, 0, 0, 1587, 1589, 3, 188, 94, 0, 1588, 1586, 1, 0, 0, 0, 1589,\n\t\t1592, 1, 0, 0, 0, 1590, 1588, 1, 0, 0, 0, 1590, 1591, 1, 0, 0, 0, 1591,\n\t\t1593, 1, 0, 0, 0, 1592, 1590, 1, 0, 0, 0, 1593, 1594, 5, 4, 0, 0, 1594,\n\t\t111, 1, 0, 0, 0, 1595, 1597, 3, 48, 24, 0, 1596, 1595, 1, 0, 0, 0, 1596,\n\t\t1597, 1, 0, 0, 0, 1597, 1598, 1, 0, 0, 0, 1598, 1601, 5, 141, 0, 0, 1599,\n\t\t1600, 5, 108, 0, 0, 1600, 1602, 7, 8, 0, 0, 1601, 1599, 1, 0, 0, 0, 1601,\n\t\t1602, 1, 0, 0, 0, 1602, 1603, 1, 0, 0, 0, 1603, 1604, 3, 114, 57, 0, 1604,\n\t\t1607, 5, 131, 0, 0, 1605, 1608, 3, 188, 94, 0, 1606, 1608, 3, 110, 55,\n\t\t0, 1607, 1605, 1, 0, 0, 0, 1607, 1606, 1, 0, 0, 0, 1608, 1609, 1, 0, 0,\n\t\t0, 1609, 1610, 5, 6, 0, 0, 1610, 1621, 3, 64, 32, 0, 1611, 1614, 5, 5,\n\t\t0, 0, 1612, 1615, 3, 188, 94, 0, 1613, 1615, 3, 110, 55, 0, 1614, 1612,\n\t\t1, 0, 0, 0, 1614, 1613, 1, 0, 0, 0, 1615, 1616, 1, 0, 0, 0, 1616, 1617,\n\t\t5, 6, 0, 0, 1617, 1618, 3, 64, 32, 0, 1618, 1620, 1, 0, 0, 0, 1619, 1611,\n\t\t1, 0, 0, 0, 1620, 1623, 1, 0, 0, 0, 1621, 1619, 1, 0, 0, 0, 1621, 1622,\n\t\t1, 0, 0, 0, 1622, 1626, 1, 0, 0, 0, 1623, 1621, 1, 0, 0, 0, 1624, 1625,\n\t\t5, 148, 0, 0, 1625, 1627, 3, 64, 32, 0, 1626, 1624, 1, 0, 0, 0, 1626, 1627,\n\t\t1, 0, 0, 0, 1627, 1629, 1, 0, 0, 0, 1628, 1630, 3, 72, 36, 0, 1629, 1628,\n\t\t1, 0, 0, 0, 1629, 1630, 1, 0, 0, 0, 1630, 1635, 1, 0, 0, 0, 1631, 1633,\n\t\t3, 136, 68, 0, 1632, 1631, 1, 0, 0, 0, 1632, 1633, 1, 0, 0, 0, 1633, 1634,\n\t\t1, 0, 0, 0, 1634, 1636, 3, 138, 69, 0, 1635, 1632, 1, 0, 0, 0, 1635, 1636,\n\t\t1, 0, 0, 0, 1636, 113, 1, 0, 0, 0, 1637, 1638, 3, 182, 91, 0, 1638, 1639,\n\t\t5, 2, 0, 0, 1639, 1641, 1, 0, 0, 0, 1640, 1637, 1, 0, 0, 0, 1640, 1641,\n\t\t1, 0, 0, 0, 1641, 1642, 1, 0, 0, 0, 1642, 1645, 3, 184, 92, 0, 1643, 1644,\n\t\t5, 33, 0, 0, 1644, 1646, 3, 212, 106, 0, 1645, 1643, 1, 0, 0, 0, 1645,\n\t\t1646, 1, 0, 0, 0, 1646, 1652, 1, 0, 0, 0, 1647, 1648, 5, 85, 0, 0, 1648,\n\t\t1649, 5, 40, 0, 0, 1649, 1653, 3, 194, 97, 0, 1650, 1651, 5, 102, 0, 0,\n\t\t1651, 1653, 5, 85, 0, 0, 1652, 1647, 1, 0, 0, 0, 1652, 1650, 1, 0, 0, 0,\n\t\t1652, 1653, 1, 0, 0, 0, 1653, 115, 1, 0, 0, 0, 1654, 1656, 5, 143, 0, 0,\n\t\t1655, 1657, 3, 182, 91, 0, 1656, 1655, 1, 0, 0, 0, 1656, 1657, 1, 0, 0,\n\t\t0, 1657, 1660, 1, 0, 0, 0, 1658, 1659, 5, 91, 0, 0, 1659, 1661, 3, 214,\n\t\t107, 0, 1660, 1658, 1, 0, 0, 0, 1660, 1661, 1, 0, 0, 0, 1661, 117, 1, 0,\n\t\t0, 0, 1662, 1663, 5, 178, 0, 0, 1663, 1664, 5, 3, 0, 0, 1664, 1665, 5,\n\t\t148, 0, 0, 1665, 1666, 3, 64, 32, 0, 1666, 1667, 5, 4, 0, 0, 1667, 119,\n\t\t1, 0, 0, 0, 1668, 1670, 5, 3, 0, 0, 1669, 1671, 3, 216, 108, 0, 1670, 1669,\n\t\t1, 0, 0, 0, 1670, 1671, 1, 0, 0, 0, 1671, 1682, 1, 0, 0, 0, 1672, 1673,\n\t\t5, 153, 0, 0, 1673, 1674, 5, 40, 0, 0, 1674, 1679, 3, 64, 32, 0, 1675,\n\t\t1676, 5, 5, 0, 0, 1676, 1678, 3, 64, 32, 0, 1677, 1675, 1, 0, 0, 0, 1678,\n\t\t1681, 1, 0, 0, 0, 1679, 1677, 1, 0, 0, 0, 1679, 1680, 1, 0, 0, 0, 1680,\n\t\t1683, 1, 0, 0, 0, 1681, 1679, 1, 0, 0, 0, 1682, 1672, 1, 0, 0, 0, 1682,\n\t\t1683, 1, 0, 0, 0, 1683, 1684, 1, 0, 0, 0, 1684, 1685, 5, 109, 0, 0, 1685,\n\t\t1686, 5, 40, 0, 0, 1686, 1691, 3, 140, 70, 0, 1687, 1688, 5, 5, 0, 0, 1688,\n\t\t1690, 3, 140, 70, 0, 1689, 1687, 1, 0, 0, 0, 1690, 1693, 1, 0, 0, 0, 1691,\n\t\t1689, 1, 0, 0, 0, 1691, 1692, 1, 0, 0, 0, 1692, 1695, 1, 0, 0, 0, 1693,\n\t\t1691, 1, 0, 0, 0, 1694, 1696, 3, 124, 62, 0, 1695, 1694, 1, 0, 0, 0, 1695,\n\t\t1696, 1, 0, 0, 0, 1696, 1697, 1, 0, 0, 0, 1697, 1698, 5, 4, 0, 0, 1698,\n\t\t121, 1, 0, 0, 0, 1699, 1733, 5, 152, 0, 0, 1700, 1734, 3, 210, 105, 0,\n\t\t1701, 1703, 5, 3, 0, 0, 1702, 1704, 3, 216, 108, 0, 1703, 1702, 1, 0, 0,\n\t\t0, 1703, 1704, 1, 0, 0, 0, 1704, 1715, 1, 0, 0, 0, 1705, 1706, 5, 153,\n\t\t0, 0, 1706, 1707, 5, 40, 0, 0, 1707, 1712, 3, 64, 32, 0, 1708, 1709, 5,\n\t\t5, 0, 0, 1709, 1711, 3, 64, 32, 0, 1710, 1708, 1, 0, 0, 0, 1711, 1714,\n\t\t1, 0, 0, 0, 1712, 1710, 1, 0, 0, 0, 1712, 1713, 1, 0, 0, 0, 1713, 1716,\n\t\t1, 0, 0, 0, 1714, 1712, 1, 0, 0, 0, 1715, 1705, 1, 0, 0, 0, 1715, 1716,\n\t\t1, 0, 0, 0, 1716, 1727, 1, 0, 0, 0, 1717, 1718, 5, 109, 0, 0, 1718, 1719,\n\t\t5, 40, 0, 0, 1719, 1724, 3, 140, 70, 0, 1720, 1721, 5, 5, 0, 0, 1721, 1723,\n\t\t3, 140, 70, 0, 1722, 1720, 1, 0, 0, 0, 1723, 1726, 1, 0, 0, 0, 1724, 1722,\n\t\t1, 0, 0, 0, 1724, 1725, 1, 0, 0, 0, 1725, 1728, 1, 0, 0, 0, 1726, 1724,\n\t\t1, 0, 0, 0, 1727, 1717, 1, 0, 0, 0, 1727, 1728, 1, 0, 0, 0, 1728, 1730,\n\t\t1, 0, 0, 0, 1729, 1731, 3, 124, 62, 0, 1730, 1729, 1, 0, 0, 0, 1730, 1731,\n\t\t1, 0, 0, 0, 1731, 1732, 1, 0, 0, 0, 1732, 1734, 5, 4, 0, 0, 1733, 1700,\n\t\t1, 0, 0, 0, 1733, 1701, 1, 0, 0, 0, 1734, 123, 1, 0, 0, 0, 1735, 1743,\n\t\t3, 126, 63, 0, 1736, 1737, 5, 180, 0, 0, 1737, 1738, 5, 101, 0, 0, 1738,\n\t\t1744, 5, 182, 0, 0, 1739, 1740, 5, 157, 0, 0, 1740, 1744, 5, 127, 0, 0,\n\t\t1741, 1744, 5, 78, 0, 0, 1742, 1744, 5, 181, 0, 0, 1743, 1736, 1, 0, 0,\n\t\t0, 1743, 1739, 1, 0, 0, 0, 1743, 1741, 1, 0, 0, 0, 1743, 1742, 1, 0, 0,\n\t\t0, 1743, 1744, 1, 0, 0, 0, 1744, 125, 1, 0, 0, 0, 1745, 1752, 7, 17, 0,\n\t\t0, 1746, 1753, 3, 148, 74, 0, 1747, 1748, 5, 39, 0, 0, 1748, 1749, 3, 144,\n\t\t72, 0, 1749, 1750, 5, 32, 0, 0, 1750, 1751, 3, 146, 73, 0, 1751, 1753,\n\t\t1, 0, 0, 0, 1752, 1746, 1, 0, 0, 0, 1752, 1747, 1, 0, 0, 0, 1753, 127,\n\t\t1, 0, 0, 0, 1754, 1755, 3, 218, 109, 0, 1755, 1765, 5, 3, 0, 0, 1756, 1761,\n\t\t3, 64, 32, 0, 1757, 1758, 5, 5, 0, 0, 1758, 1760, 3, 64, 32, 0, 1759, 1757,\n\t\t1, 0, 0, 0, 1760, 1763, 1, 0, 0, 0, 1761, 1759, 1, 0, 0, 0, 1761, 1762,\n\t\t1, 0, 0, 0, 1762, 1766, 1, 0, 0, 0, 1763, 1761, 1, 0, 0, 0, 1764, 1766,\n\t\t5, 7, 0, 0, 1765, 1756, 1, 0, 0, 0, 1765, 1764, 1, 0, 0, 0, 1766, 1767,\n\t\t1, 0, 0, 0, 1767, 1768, 5, 4, 0, 0, 1768, 129, 1, 0, 0, 0, 1769, 1770,\n\t\t3, 220, 110, 0, 1770, 1783, 5, 3, 0, 0, 1771, 1773, 5, 62, 0, 0, 1772,\n\t\t1771, 1, 0, 0, 0, 1772, 1773, 1, 0, 0, 0, 1773, 1774, 1, 0, 0, 0, 1774,\n\t\t1779, 3, 64, 32, 0, 1775, 1776, 5, 5, 0, 0, 1776, 1778, 3, 64, 32, 0, 1777,\n\t\t1775, 1, 0, 0, 0, 1778, 1781, 1, 0, 0, 0, 1779, 1777, 1, 0, 0, 0, 1779,\n\t\t1780, 1, 0, 0, 0, 1780, 1784, 1, 0, 0, 0, 1781, 1779, 1, 0, 0, 0, 1782,\n\t\t1784, 5, 7, 0, 0, 1783, 1772, 1, 0, 0, 0, 1783, 1782, 1, 0, 0, 0, 1783,\n\t\t1784, 1, 0, 0, 0, 1784, 1785, 1, 0, 0, 0, 1785, 1787, 5, 4, 0, 0, 1786,\n\t\t1788, 3, 118, 59, 0, 1787, 1786, 1, 0, 0, 0, 1787, 1788, 1, 0, 0, 0, 1788,\n\t\t131, 1, 0, 0, 0, 1789, 1790, 3, 150, 75, 0, 1790, 1800, 5, 3, 0, 0, 1791,\n\t\t1796, 3, 64, 32, 0, 1792, 1793, 5, 5, 0, 0, 1793, 1795, 3, 64, 32, 0, 1794,\n\t\t1792, 1, 0, 0, 0, 1795, 1798, 1, 0, 0, 0, 1796, 1794, 1, 0, 0, 0, 1796,\n\t\t1797, 1, 0, 0, 0, 1797, 1801, 1, 0, 0, 0, 1798, 1796, 1, 0, 0, 0, 1799,\n\t\t1801, 5, 7, 0, 0, 1800, 1791, 1, 0, 0, 0, 1800, 1799, 1, 0, 0, 0, 1800,\n\t\t1801, 1, 0, 0, 0, 1801, 1802, 1, 0, 0, 0, 1802, 1804, 5, 4, 0, 0, 1803,\n\t\t1805, 3, 118, 59, 0, 1804, 1803, 1, 0, 0, 0, 1804, 1805, 1, 0, 0, 0, 1805,\n\t\t1806, 1, 0, 0, 0, 1806, 1809, 5, 152, 0, 0, 1807, 1810, 3, 120, 60, 0,\n\t\t1808, 1810, 3, 210, 105, 0, 1809, 1807, 1, 0, 0, 0, 1809, 1808, 1, 0, 0,\n\t\t0, 1810, 133, 1, 0, 0, 0, 1811, 1813, 5, 149, 0, 0, 1812, 1814, 5, 116,\n\t\t0, 0, 1813, 1812, 1, 0, 0, 0, 1813, 1814, 1, 0, 0, 0, 1814, 1815, 1, 0,\n\t\t0, 0, 1815, 1820, 3, 54, 27, 0, 1816, 1817, 5, 5, 0, 0, 1817, 1819, 3,\n\t\t54, 27, 0, 1818, 1816, 1, 0, 0, 0, 1819, 1822, 1, 0, 0, 0, 1820, 1818,\n\t\t1, 0, 0, 0, 1820, 1821, 1, 0, 0, 0, 1821, 135, 1, 0, 0, 0, 1822, 1820,\n\t\t1, 0, 0, 0, 1823, 1824, 5, 109, 0, 0, 1824, 1825, 5, 40, 0, 0, 1825, 1830,\n\t\t3, 140, 70, 0, 1826, 1827, 5, 5, 0, 0, 1827, 1829, 3, 140, 70, 0, 1828,\n\t\t1826, 1, 0, 0, 0, 1829, 1832, 1, 0, 0, 0, 1830, 1828, 1, 0, 0, 0, 1830,\n\t\t1831, 1, 0, 0, 0, 1831, 137, 1, 0, 0, 0, 1832, 1830, 1, 0, 0, 0, 1833,\n\t\t1834, 5, 98, 0, 0, 1834, 1837, 3, 64, 32, 0, 1835, 1836, 7, 18, 0, 0, 1836,\n\t\t1838, 3, 64, 32, 0, 1837, 1835, 1, 0, 0, 0, 1837, 1838, 1, 0, 0, 0, 1838,\n\t\t139, 1, 0, 0, 0, 1839, 1842, 3, 64, 32, 0, 1840, 1841, 5, 45, 0, 0, 1841,\n\t\t1843, 3, 190, 95, 0, 1842, 1840, 1, 0, 0, 0, 1842, 1843, 1, 0, 0, 0, 1843,\n\t\t1845, 1, 0, 0, 0, 1844, 1846, 3, 142, 71, 0, 1845, 1844, 1, 0, 0, 0, 1845,\n\t\t1846, 1, 0, 0, 0, 1846, 1849, 1, 0, 0, 0, 1847, 1848, 5, 175, 0, 0, 1848,\n\t\t1850, 7, 19, 0, 0, 1849, 1847, 1, 0, 0, 0, 1849, 1850, 1, 0, 0, 0, 1850,\n\t\t141, 1, 0, 0, 0, 1851, 1852, 7, 20, 0, 0, 1852, 143, 1, 0, 0, 0, 1853,\n\t\t1854, 3, 64, 32, 0, 1854, 1855, 5, 155, 0, 0, 1855, 1864, 1, 0, 0, 0, 1856,\n\t\t1857, 3, 64, 32, 0, 1857, 1858, 5, 158, 0, 0, 1858, 1864, 1, 0, 0, 0, 1859,\n\t\t1860, 5, 157, 0, 0, 1860, 1864, 5, 127, 0, 0, 1861, 1862, 5, 156, 0, 0,\n\t\t1862, 1864, 5, 155, 0, 0, 1863, 1853, 1, 0, 0, 0, 1863, 1856, 1, 0, 0,\n\t\t0, 1863, 1859, 1, 0, 0, 0, 1863, 1861, 1, 0, 0, 0, 1864, 145, 1, 0, 0,\n\t\t0, 1865, 1866, 3, 64, 32, 0, 1866, 1867, 5, 155, 0, 0, 1867, 1876, 1, 0,\n\t\t0, 0, 1868, 1869, 3, 64, 32, 0, 1869, 1870, 5, 158, 0, 0, 1870, 1876, 1,\n\t\t0, 0, 0, 1871, 1872, 5, 157, 0, 0, 1872, 1876, 5, 127, 0, 0, 1873, 1874,\n\t\t5, 156, 0, 0, 1874, 1876, 5, 158, 0, 0, 1875, 1865, 1, 0, 0, 0, 1875, 1868,\n\t\t1, 0, 0, 0, 1875, 1871, 1, 0, 0, 0, 1875, 1873, 1, 0, 0, 0, 1876, 147,\n\t\t1, 0, 0, 0, 1877, 1878, 3, 64, 32, 0, 1878, 1879, 5, 155, 0, 0, 1879, 1885,\n\t\t1, 0, 0, 0, 1880, 1881, 5, 156, 0, 0, 1881, 1885, 5, 155, 0, 0, 1882, 1883,\n\t\t5, 157, 0, 0, 1883, 1885, 5, 127, 0, 0, 1884, 1877, 1, 0, 0, 0, 1884, 1880,\n\t\t1, 0, 0, 0, 1884, 1882, 1, 0, 0, 0, 1885, 149, 1, 0, 0, 0, 1886, 1887,\n\t\t7, 21, 0, 0, 1887, 1888, 5, 3, 0, 0, 1888, 1889, 3, 64, 32, 0, 1889, 1890,\n\t\t5, 4, 0, 0, 1890, 1891, 5, 152, 0, 0, 1891, 1893, 5, 3, 0, 0, 1892, 1894,\n\t\t3, 156, 78, 0, 1893, 1892, 1, 0, 0, 0, 1893, 1894, 1, 0, 0, 0, 1894, 1895,\n\t\t1, 0, 0, 0, 1895, 1897, 3, 160, 80, 0, 1896, 1898, 3, 126, 63, 0, 1897,\n\t\t1896, 1, 0, 0, 0, 1897, 1898, 1, 0, 0, 0, 1898, 1899, 1, 0, 0, 0, 1899,\n\t\t1900, 5, 4, 0, 0, 1900, 1972, 1, 0, 0, 0, 1901, 1902, 7, 22, 0, 0, 1902,\n\t\t1903, 5, 3, 0, 0, 1903, 1904, 5, 4, 0, 0, 1904, 1905, 5, 152, 0, 0, 1905,\n\t\t1907, 5, 3, 0, 0, 1906, 1908, 3, 156, 78, 0, 1907, 1906, 1, 0, 0, 0, 1907,\n\t\t1908, 1, 0, 0, 0, 1908, 1910, 1, 0, 0, 0, 1909, 1911, 3, 158, 79, 0, 1910,\n\t\t1909, 1, 0, 0, 0, 1910, 1911, 1, 0, 0, 0, 1911, 1912, 1, 0, 0, 0, 1912,\n\t\t1972, 5, 4, 0, 0, 1913, 1914, 7, 23, 0, 0, 1914, 1915, 5, 3, 0, 0, 1915,\n\t\t1916, 5, 4, 0, 0, 1916, 1917, 5, 152, 0, 0, 1917, 1919, 5, 3, 0, 0, 1918,\n\t\t1920, 3, 156, 78, 0, 1919, 1918, 1, 0, 0, 0, 1919, 1920, 1, 0, 0, 0, 1920,\n\t\t1921, 1, 0, 0, 0, 1921, 1922, 3, 160, 80, 0, 1922, 1923, 5, 4, 0, 0, 1923,\n\t\t1972, 1, 0, 0, 0, 1924, 1925, 7, 24, 0, 0, 1925, 1926, 5, 3, 0, 0, 1926,\n\t\t1928, 3, 64, 32, 0, 1927, 1929, 3, 152, 76, 0, 1928, 1927, 1, 0, 0, 0,\n\t\t1928, 1929, 1, 0, 0, 0, 1929, 1931, 1, 0, 0, 0, 1930, 1932, 3, 154, 77,\n\t\t0, 1931, 1930, 1, 0, 0, 0, 1931, 1932, 1, 0, 0, 0, 1932, 1933, 1, 0, 0,\n\t\t0, 1933, 1934, 5, 4, 0, 0, 1934, 1935, 5, 152, 0, 0, 1935, 1937, 5, 3,\n\t\t0, 0, 1936, 1938, 3, 156, 78, 0, 1937, 1936, 1, 0, 0, 0, 1937, 1938, 1,\n\t\t0, 0, 0, 1938, 1939, 1, 0, 0, 0, 1939, 1940, 3, 160, 80, 0, 1940, 1941,\n\t\t5, 4, 0, 0, 1941, 1972, 1, 0, 0, 0, 1942, 1943, 5, 164, 0, 0, 1943, 1944,\n\t\t5, 3, 0, 0, 1944, 1945, 3, 64, 32, 0, 1945, 1946, 5, 5, 0, 0, 1946, 1947,\n\t\t3, 34, 17, 0, 1947, 1948, 5, 4, 0, 0, 1948, 1949, 5, 152, 0, 0, 1949, 1951,\n\t\t5, 3, 0, 0, 1950, 1952, 3, 156, 78, 0, 1951, 1950, 1, 0, 0, 0, 1951, 1952,\n\t\t1, 0, 0, 0, 1952, 1953, 1, 0, 0, 0, 1953, 1955, 3, 160, 80, 0, 1954, 1956,\n\t\t3, 126, 63, 0, 1955, 1954, 1, 0, 0, 0, 1955, 1956, 1, 0, 0, 0, 1956, 1957,\n\t\t1, 0, 0, 0, 1957, 1958, 5, 4, 0, 0, 1958, 1972, 1, 0, 0, 0, 1959, 1960,\n\t\t5, 165, 0, 0, 1960, 1961, 5, 3, 0, 0, 1961, 1962, 3, 64, 32, 0, 1962, 1963,\n\t\t5, 4, 0, 0, 1963, 1964, 5, 152, 0, 0, 1964, 1966, 5, 3, 0, 0, 1965, 1967,\n\t\t3, 156, 78, 0, 1966, 1965, 1, 0, 0, 0, 1966, 1967, 1, 0, 0, 0, 1967, 1968,\n\t\t1, 0, 0, 0, 1968, 1969, 3, 160, 80, 0, 1969, 1970, 5, 4, 0, 0, 1970, 1972,\n\t\t1, 0, 0, 0, 1971, 1886, 1, 0, 0, 0, 1971, 1901, 1, 0, 0, 0, 1971, 1913,\n\t\t1, 0, 0, 0, 1971, 1924, 1, 0, 0, 0, 1971, 1942, 1, 0, 0, 0, 1971, 1959,\n\t\t1, 0, 0, 0, 1972, 151, 1, 0, 0, 0, 1973, 1974, 5, 5, 0, 0, 1974, 1975,\n\t\t3, 34, 17, 0, 1975, 153, 1, 0, 0, 0, 1976, 1977, 5, 5, 0, 0, 1977, 1978,\n\t\t3, 34, 17, 0, 1978, 155, 1, 0, 0, 0, 1979, 1980, 5, 153, 0, 0, 1980, 1982,\n\t\t5, 40, 0, 0, 1981, 1983, 3, 64, 32, 0, 1982, 1981, 1, 0, 0, 0, 1983, 1984,\n\t\t1, 0, 0, 0, 1984, 1982, 1, 0, 0, 0, 1984, 1985, 1, 0, 0, 0, 1985, 157,\n\t\t1, 0, 0, 0, 1986, 1987, 5, 109, 0, 0, 1987, 1989, 5, 40, 0, 0, 1988, 1990,\n\t\t3, 64, 32, 0, 1989, 1988, 1, 0, 0, 0, 1990, 1991, 1, 0, 0, 0, 1991, 1989,\n\t\t1, 0, 0, 0, 1991, 1992, 1, 0, 0, 0, 1992, 159, 1, 0, 0, 0, 1993, 1994,\n\t\t5, 109, 0, 0, 1994, 1995, 5, 40, 0, 0, 1995, 1996, 3, 162, 81, 0, 1996,\n\t\t161, 1, 0, 0, 0, 1997, 1999, 3, 64, 32, 0, 1998, 2000, 3, 142, 71, 0, 1999,\n\t\t1998, 1, 0, 0, 0, 1999, 2000, 1, 0, 0, 0, 2000, 2008, 1, 0, 0, 0, 2001,\n\t\t2002, 5, 5, 0, 0, 2002, 2004, 3, 64, 32, 0, 2003, 2005, 3, 142, 71, 0,\n\t\t2004, 2003, 1, 0, 0, 0, 2004, 2005, 1, 0, 0, 0, 2005, 2007, 1, 0, 0, 0,\n\t\t2006, 2001, 1, 0, 0, 0, 2007, 2010, 1, 0, 0, 0, 2008, 2006, 1, 0, 0, 0,\n\t\t2008, 2009, 1, 0, 0, 0, 2009, 163, 1, 0, 0, 0, 2010, 2008, 1, 0, 0, 0,\n\t\t2011, 2012, 3, 82, 41, 0, 2012, 165, 1, 0, 0, 0, 2013, 2014, 3, 82, 41,\n\t\t0, 2014, 167, 1, 0, 0, 0, 2015, 2016, 7, 25, 0, 0, 2016, 169, 1, 0, 0,\n\t\t0, 2017, 2018, 5, 188, 0, 0, 2018, 171, 1, 0, 0, 0, 2019, 2022, 3, 64,\n\t\t32, 0, 2020, 2022, 3, 28, 14, 0, 2021, 2019, 1, 0, 0, 0, 2021, 2020, 1,\n\t\t0, 0, 0, 2022, 173, 1, 0, 0, 0, 2023, 2024, 7, 26, 0, 0, 2024, 175, 1,\n\t\t0, 0, 0, 2025, 2026, 7, 27, 0, 0, 2026, 177, 1, 0, 0, 0, 2027, 2028, 3,\n\t\t224, 112, 0, 2028, 179, 1, 0, 0, 0, 2029, 2030, 3, 224, 112, 0, 2030, 181,\n\t\t1, 0, 0, 0, 2031, 2032, 3, 224, 112, 0, 2032, 183, 1, 0, 0, 0, 2033, 2034,\n\t\t3, 224, 112, 0, 2034, 185, 1, 0, 0, 0, 2035, 2036, 3, 224, 112, 0, 2036,\n\t\t187, 1, 0, 0, 0, 2037, 2038, 3, 224, 112, 0, 2038, 189, 1, 0, 0, 0, 2039,\n\t\t2040, 3, 224, 112, 0, 2040, 191, 1, 0, 0, 0, 2041, 2042, 3, 224, 112, 0,\n\t\t2042, 193, 1, 0, 0, 0, 2043, 2044, 3, 224, 112, 0, 2044, 195, 1, 0, 0,\n\t\t0, 2045, 2046, 3, 224, 112, 0, 2046, 197, 1, 0, 0, 0, 2047, 2048, 3, 224,\n\t\t112, 0, 2048, 199, 1, 0, 0, 0, 2049, 2050, 3, 224, 112, 0, 2050, 201, 1,\n\t\t0, 0, 0, 2051, 2052, 3, 224, 112, 0, 2052, 203, 1, 0, 0, 0, 2053, 2054,\n\t\t3, 224, 112, 0, 2054, 205, 1, 0, 0, 0, 2055, 2056, 3, 224, 112, 0, 2056,\n\t\t207, 1, 0, 0, 0, 2057, 2058, 3, 224, 112, 0, 2058, 209, 1, 0, 0, 0, 2059,\n\t\t2060, 3, 224, 112, 0, 2060, 211, 1, 0, 0, 0, 2061, 2062, 3, 224, 112, 0,\n\t\t2062, 213, 1, 0, 0, 0, 2063, 2064, 3, 224, 112, 0, 2064, 215, 1, 0, 0,\n\t\t0, 2065, 2066, 3, 224, 112, 0, 2066, 217, 1, 0, 0, 0, 2067, 2068, 3, 224,\n\t\t112, 0, 2068, 219, 1, 0, 0, 0, 2069, 2070, 3, 224, 112, 0, 2070, 221, 1,\n\t\t0, 0, 0, 2071, 2072, 3, 224, 112, 0, 2072, 223, 1, 0, 0, 0, 2073, 2081,\n\t\t5, 185, 0, 0, 2074, 2081, 3, 176, 88, 0, 2075, 2081, 5, 188, 0, 0, 2076,\n\t\t2077, 5, 3, 0, 0, 2077, 2078, 3, 224, 112, 0, 2078, 2079, 5, 4, 0, 0, 2079,\n\t\t2081, 1, 0, 0, 0, 2080, 2073, 1, 0, 0, 0, 2080, 2074, 1, 0, 0, 0, 2080,\n\t\t2075, 1, 0, 0, 0, 2080, 2076, 1, 0, 0, 0, 2081, 225, 1, 0, 0, 0, 297, 229,\n\t\t237, 244, 249, 255, 261, 263, 289, 296, 303, 309, 313, 318, 321, 328, 331,\n\t\t335, 343, 347, 349, 353, 357, 361, 364, 371, 377, 383, 388, 399, 405, 409,\n\t\t413, 416, 420, 426, 431, 440, 447, 453, 457, 461, 466, 472, 484, 488, 493,\n\t\t496, 499, 504, 507, 521, 528, 535, 537, 540, 546, 551, 559, 564, 579, 585,\n\t\t595, 600, 610, 614, 616, 620, 625, 627, 635, 641, 646, 653, 664, 667, 669,\n\t\t676, 680, 687, 693, 699, 705, 710, 719, 724, 735, 740, 751, 756, 760, 776,\n\t\t786, 791, 799, 811, 816, 824, 831, 834, 837, 844, 847, 850, 853, 857, 865,\n\t\t870, 880, 885, 894, 901, 905, 909, 912, 920, 933, 936, 944, 953, 957, 962,\n\t\t992, 1004, 1009, 1021, 1027, 1034, 1038, 1048, 1051, 1057, 1063, 1072,\n\t\t1075, 1079, 1081, 1083, 1092, 1099, 1106, 1112, 1117, 1125, 1130, 1139,\n\t\t1150, 1157, 1161, 1164, 1168, 1171, 1179, 1190, 1196, 1198, 1206, 1213,\n\t\t1220, 1225, 1227, 1233, 1242, 1247, 1254, 1258, 1260, 1263, 1271, 1275,\n\t\t1278, 1284, 1288, 1293, 1300, 1309, 1313, 1315, 1319, 1328, 1333, 1335,\n\t\t1348, 1351, 1360, 1371, 1378, 1381, 1386, 1390, 1393, 1396, 1401, 1405,\n\t\t1410, 1413, 1416, 1421, 1425, 1428, 1435, 1440, 1449, 1454, 1457, 1465,\n\t\t1469, 1477, 1480, 1482, 1491, 1494, 1496, 1500, 1504, 1508, 1511, 1522,\n\t\t1527, 1531, 1535, 1538, 1543, 1554, 1558, 1560, 1564, 1567, 1574, 1579,\n\t\t1590, 1596, 1601, 1607, 1614, 1621, 1626, 1629, 1632, 1635, 1640, 1645,\n\t\t1652, 1656, 1660, 1670, 1679, 1682, 1691, 1695, 1703, 1712, 1715, 1724,\n\t\t1727, 1730, 1733, 1743, 1752, 1761, 1765, 1772, 1779, 1783, 1787, 1796,\n\t\t1800, 1804, 1809, 1813, 1820, 1830, 1837, 1842, 1845, 1849, 1863, 1875,\n\t\t1884, 1893, 1897, 1907, 1910, 1919, 1928, 1931, 1937, 1951, 1955, 1966,\n\t\t1971, 1984, 1991, 1999, 2004, 2008, 2021, 2080,\n\t}\n\tdeserializer := antlr.NewATNDeserializer(nil)\n\tstaticData.atn = deserializer.Deserialize(staticData.serializedATN)\n\tatn := staticData.atn\n\tstaticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState))\n\tdecisionToDFA := staticData.decisionToDFA\n\tfor index, state := range atn.DecisionToState {\n\t\tdecisionToDFA[index] = antlr.NewDFA(state, index)\n\t}\n}\n\n// ParserInit initializes any static state used to implement Parser. By default the\n// static state used to implement the parser is lazily initialized during the first call to\n// NewParser(). You can call this function if you wish to initialize the static state ahead\n// of time.\nfunc ParserInit() {\n\tstaticData := &ParserParserStaticData\n\tstaticData.once.Do(parserParserInit)\n}\n\n// NewParser produces a new parser instance for the optional input antlr.TokenStream.\nfunc NewParser(input antlr.TokenStream) *Parser {\n\tParserInit()\n\tthis := new(Parser)\n\tthis.BaseParser = antlr.NewBaseParser(input)\n\tstaticData := &ParserParserStaticData\n\tthis.Interpreter = antlr.NewParserATNSimulator(this, staticData.atn, staticData.decisionToDFA, staticData.PredictionContextCache)\n\tthis.RuleNames = staticData.RuleNames\n\tthis.LiteralNames = staticData.LiteralNames\n\tthis.SymbolicNames = staticData.SymbolicNames\n\tthis.GrammarFileName = \"Parser.g4\"\n\n\treturn this\n}\n\n// Parser tokens.\nconst (\n\tParserEOF                 = antlr.TokenEOF\n\tParserSCOL                = 1\n\tParserDOT                 = 2\n\tParserOPEN_PAR            = 3\n\tParserCLOSE_PAR           = 4\n\tParserCOMMA               = 5\n\tParserASSIGN              = 6\n\tParserSTAR                = 7\n\tParserPLUS                = 8\n\tParserMINUS               = 9\n\tParserTILDE               = 10\n\tParserPIPE2               = 11\n\tParserDIV                 = 12\n\tParserMOD                 = 13\n\tParserLT2                 = 14\n\tParserGT2                 = 15\n\tParserAMP                 = 16\n\tParserPIPE                = 17\n\tParserLT                  = 18\n\tParserLT_EQ               = 19\n\tParserGT                  = 20\n\tParserGT_EQ               = 21\n\tParserEQ                  = 22\n\tParserNOT_EQ1             = 23\n\tParserNOT_EQ2             = 24\n\tParserABORT_              = 25\n\tParserACTION_             = 26\n\tParserADD_                = 27\n\tParserAFTER_              = 28\n\tParserALL_                = 29\n\tParserALTER_              = 30\n\tParserANALYZE_            = 31\n\tParserAND_                = 32\n\tParserAS_                 = 33\n\tParserASC_                = 34\n\tParserATTACH_             = 35\n\tParserAUTOINCREMENT_      = 36\n\tParserBEFORE_             = 37\n\tParserBEGIN_              = 38\n\tParserBETWEEN_            = 39\n\tParserBY_                 = 40\n\tParserCASCADE_            = 41\n\tParserCASE_               = 42\n\tParserCAST_               = 43\n\tParserCHECK_              = 44\n\tParserCOLLATE_            = 45\n\tParserCOLUMN_             = 46\n\tParserCOMMIT_             = 47\n\tParserCONFLICT_           = 48\n\tParserCONSTRAINT_         = 49\n\tParserCREATE_             = 50\n\tParserCROSS_              = 51\n\tParserCURRENT_DATE_       = 52\n\tParserCURRENT_TIME_       = 53\n\tParserCURRENT_TIMESTAMP_  = 54\n\tParserDATABASE_           = 55\n\tParserDEFAULT_            = 56\n\tParserDEFERRABLE_         = 57\n\tParserDEFERRED_           = 58\n\tParserDELETE_             = 59\n\tParserDESC_               = 60\n\tParserDETACH_             = 61\n\tParserDISTINCT_           = 62\n\tParserDROP_               = 63\n\tParserEACH_               = 64\n\tParserELSE_               = 65\n\tParserEND_                = 66\n\tParserESCAPE_             = 67\n\tParserEXCEPT_             = 68\n\tParserEXCLUSIVE_          = 69\n\tParserEXISTS_             = 70\n\tParserEXPLAIN_            = 71\n\tParserFAIL_               = 72\n\tParserFOR_                = 73\n\tParserFOREIGN_            = 74\n\tParserFROM_               = 75\n\tParserFULL_               = 76\n\tParserGLOB_               = 77\n\tParserGROUP_              = 78\n\tParserHAVING_             = 79\n\tParserIF_                 = 80\n\tParserIGNORE_             = 81\n\tParserIMMEDIATE_          = 82\n\tParserIN_                 = 83\n\tParserINDEX_              = 84\n\tParserINDEXED_            = 85\n\tParserINITIALLY_          = 86\n\tParserINNER_              = 87\n\tParserINSERT_             = 88\n\tParserINSTEAD_            = 89\n\tParserINTERSECT_          = 90\n\tParserINTO_               = 91\n\tParserIS_                 = 92\n\tParserISNULL_             = 93\n\tParserJOIN_               = 94\n\tParserKEY_                = 95\n\tParserLEFT_               = 96\n\tParserLIKE_               = 97\n\tParserLIMIT_              = 98\n\tParserMATCH_              = 99\n\tParserNATURAL_            = 100\n\tParserNO_                 = 101\n\tParserNOT_                = 102\n\tParserNOTNULL_            = 103\n\tParserNULL_               = 104\n\tParserOF_                 = 105\n\tParserOFFSET_             = 106\n\tParserON_                 = 107\n\tParserOR_                 = 108\n\tParserORDER_              = 109\n\tParserOUTER_              = 110\n\tParserPLAN_               = 111\n\tParserPRAGMA_             = 112\n\tParserPRIMARY_            = 113\n\tParserQUERY_              = 114\n\tParserRAISE_              = 115\n\tParserRECURSIVE_          = 116\n\tParserREFERENCES_         = 117\n\tParserREGEXP_             = 118\n\tParserREINDEX_            = 119\n\tParserRELEASE_            = 120\n\tParserRENAME_             = 121\n\tParserREPLACE_            = 122\n\tParserRESTRICT_           = 123\n\tParserRETURNING_          = 124\n\tParserRIGHT_              = 125\n\tParserROLLBACK_           = 126\n\tParserROW_                = 127\n\tParserROWS_               = 128\n\tParserSAVEPOINT_          = 129\n\tParserSELECT_             = 130\n\tParserSET_                = 131\n\tParserTABLE_              = 132\n\tParserTEMP_               = 133\n\tParserTEMPORARY_          = 134\n\tParserTHEN_               = 135\n\tParserTO_                 = 136\n\tParserTRANSACTION_        = 137\n\tParserTRIGGER_            = 138\n\tParserUNION_              = 139\n\tParserUNIQUE_             = 140\n\tParserUPDATE_             = 141\n\tParserUSING_              = 142\n\tParserVACUUM_             = 143\n\tParserVALUES_             = 144\n\tParserVIEW_               = 145\n\tParserVIRTUAL_            = 146\n\tParserWHEN_               = 147\n\tParserWHERE_              = 148\n\tParserWITH_               = 149\n\tParserWITHOUT_            = 150\n\tParserFIRST_VALUE_        = 151\n\tParserOVER_               = 152\n\tParserPARTITION_          = 153\n\tParserRANGE_              = 154\n\tParserPRECEDING_          = 155\n\tParserUNBOUNDED_          = 156\n\tParserCURRENT_            = 157\n\tParserFOLLOWING_          = 158\n\tParserCUME_DIST_          = 159\n\tParserDENSE_RANK_         = 160\n\tParserLAG_                = 161\n\tParserLAST_VALUE_         = 162\n\tParserLEAD_               = 163\n\tParserNTH_VALUE_          = 164\n\tParserNTILE_              = 165\n\tParserPERCENT_RANK_       = 166\n\tParserRANK_               = 167\n\tParserROW_NUMBER_         = 168\n\tParserGENERATED_          = 169\n\tParserALWAYS_             = 170\n\tParserSTORED_             = 171\n\tParserTRUE_               = 172\n\tParserFALSE_              = 173\n\tParserWINDOW_             = 174\n\tParserNULLS_              = 175\n\tParserFIRST_              = 176\n\tParserLAST_               = 177\n\tParserFILTER_             = 178\n\tParserGROUPS_             = 179\n\tParserEXCLUDE_            = 180\n\tParserTIES_               = 181\n\tParserOTHERS_             = 182\n\tParserDO_                 = 183\n\tParserNOTHING_            = 184\n\tParserIDENTIFIER          = 185\n\tParserNUMERIC_LITERAL     = 186\n\tParserBIND_PARAMETER      = 187\n\tParserSTRING_LITERAL      = 188\n\tParserBLOB_LITERAL        = 189\n\tParserSINGLE_LINE_COMMENT = 190\n\tParserMULTILINE_COMMENT   = 191\n\tParserSPACES              = 192\n\tParserUNEXPECTED_CHAR     = 193\n)\n\n// Parser rules.\nconst (\n\tParserRULE_parse                         = 0\n\tParserRULE_sql_stmt_list                 = 1\n\tParserRULE_sql_stmt                      = 2\n\tParserRULE_alter_table_stmt              = 3\n\tParserRULE_analyze_stmt                  = 4\n\tParserRULE_attach_stmt                   = 5\n\tParserRULE_begin_stmt                    = 6\n\tParserRULE_commit_stmt                   = 7\n\tParserRULE_rollback_stmt                 = 8\n\tParserRULE_savepoint_stmt                = 9\n\tParserRULE_release_stmt                  = 10\n\tParserRULE_create_index_stmt             = 11\n\tParserRULE_indexed_column                = 12\n\tParserRULE_create_table_stmt             = 13\n\tParserRULE_column_def                    = 14\n\tParserRULE_type_name                     = 15\n\tParserRULE_column_constraint             = 16\n\tParserRULE_signed_number                 = 17\n\tParserRULE_table_constraint              = 18\n\tParserRULE_foreign_key_clause            = 19\n\tParserRULE_conflict_clause               = 20\n\tParserRULE_create_trigger_stmt           = 21\n\tParserRULE_create_view_stmt              = 22\n\tParserRULE_create_virtual_table_stmt     = 23\n\tParserRULE_with_clause                   = 24\n\tParserRULE_cte_table_name                = 25\n\tParserRULE_recursive_cte                 = 26\n\tParserRULE_common_table_expression       = 27\n\tParserRULE_delete_stmt                   = 28\n\tParserRULE_delete_stmt_limited           = 29\n\tParserRULE_detach_stmt                   = 30\n\tParserRULE_drop_stmt                     = 31\n\tParserRULE_expr                          = 32\n\tParserRULE_raise_function                = 33\n\tParserRULE_literal_value                 = 34\n\tParserRULE_insert_stmt                   = 35\n\tParserRULE_returning_clause              = 36\n\tParserRULE_upsert_clause                 = 37\n\tParserRULE_pragma_stmt                   = 38\n\tParserRULE_pragma_value                  = 39\n\tParserRULE_reindex_stmt                  = 40\n\tParserRULE_select_stmt                   = 41\n\tParserRULE_join_clause                   = 42\n\tParserRULE_select_core                   = 43\n\tParserRULE_factored_select_stmt          = 44\n\tParserRULE_simple_select_stmt            = 45\n\tParserRULE_compound_select_stmt          = 46\n\tParserRULE_table_or_subquery             = 47\n\tParserRULE_result_column                 = 48\n\tParserRULE_join_operator                 = 49\n\tParserRULE_join_constraint               = 50\n\tParserRULE_compound_operator             = 51\n\tParserRULE_update_stmt                   = 52\n\tParserRULE_assignment_list               = 53\n\tParserRULE_assignment                    = 54\n\tParserRULE_column_name_list              = 55\n\tParserRULE_update_stmt_limited           = 56\n\tParserRULE_qualified_table_name          = 57\n\tParserRULE_vacuum_stmt                   = 58\n\tParserRULE_filter_clause                 = 59\n\tParserRULE_window_defn                   = 60\n\tParserRULE_over_clause                   = 61\n\tParserRULE_frame_spec                    = 62\n\tParserRULE_frame_clause                  = 63\n\tParserRULE_simple_function_invocation    = 64\n\tParserRULE_aggregate_function_invocation = 65\n\tParserRULE_window_function_invocation    = 66\n\tParserRULE_common_table_stmt             = 67\n\tParserRULE_order_by_stmt                 = 68\n\tParserRULE_limit_stmt                    = 69\n\tParserRULE_ordering_term                 = 70\n\tParserRULE_asc_desc                      = 71\n\tParserRULE_frame_left                    = 72\n\tParserRULE_frame_right                   = 73\n\tParserRULE_frame_single                  = 74\n\tParserRULE_window_function               = 75\n\tParserRULE_offset                        = 76\n\tParserRULE_default_value                 = 77\n\tParserRULE_partition_by                  = 78\n\tParserRULE_order_by_expr                 = 79\n\tParserRULE_order_by_expr_asc_desc        = 80\n\tParserRULE_expr_asc_desc                 = 81\n\tParserRULE_initial_select                = 82\n\tParserRULE_recursive_select              = 83\n\tParserRULE_unary_operator                = 84\n\tParserRULE_error_message                 = 85\n\tParserRULE_module_argument               = 86\n\tParserRULE_column_alias                  = 87\n\tParserRULE_keyword                       = 88\n\tParserRULE_name                          = 89\n\tParserRULE_function_name                 = 90\n\tParserRULE_schema_name                   = 91\n\tParserRULE_table_name                    = 92\n\tParserRULE_table_or_index_name           = 93\n\tParserRULE_column_name                   = 94\n\tParserRULE_collation_name                = 95\n\tParserRULE_foreign_table                 = 96\n\tParserRULE_index_name                    = 97\n\tParserRULE_trigger_name                  = 98\n\tParserRULE_view_name                     = 99\n\tParserRULE_module_name                   = 100\n\tParserRULE_pragma_name                   = 101\n\tParserRULE_savepoint_name                = 102\n\tParserRULE_table_alias                   = 103\n\tParserRULE_transaction_name              = 104\n\tParserRULE_window_name                   = 105\n\tParserRULE_alias                         = 106\n\tParserRULE_filename                      = 107\n\tParserRULE_base_window_name              = 108\n\tParserRULE_simple_func                   = 109\n\tParserRULE_aggregate_func                = 110\n\tParserRULE_table_function_name           = 111\n\tParserRULE_any_name                      = 112\n)\n\n// IParseContext is an interface to support dynamic dispatch.\ntype IParseContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tEOF() antlr.TerminalNode\n\tAllSql_stmt_list() []ISql_stmt_listContext\n\tSql_stmt_list(i int) ISql_stmt_listContext\n\n\t// IsParseContext differentiates from other interfaces.\n\tIsParseContext()\n}\n\ntype ParseContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyParseContext() *ParseContext {\n\tvar p = new(ParseContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_parse\n\treturn p\n}\n\nfunc InitEmptyParseContext(p *ParseContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_parse\n}\n\nfunc (*ParseContext) IsParseContext() {}\n\nfunc NewParseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ParseContext {\n\tvar p = new(ParseContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_parse\n\n\treturn p\n}\n\nfunc (s *ParseContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *ParseContext) EOF() antlr.TerminalNode {\n\treturn s.GetToken(ParserEOF, 0)\n}\n\nfunc (s *ParseContext) AllSql_stmt_list() []ISql_stmt_listContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ISql_stmt_listContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ISql_stmt_listContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ISql_stmt_listContext); ok {\n\t\t\ttst[i] = t.(ISql_stmt_listContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *ParseContext) Sql_stmt_list(i int) ISql_stmt_listContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISql_stmt_listContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISql_stmt_listContext)\n}\n\nfunc (s *ParseContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *ParseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *ParseContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterParse(s)\n\t}\n}\n\nfunc (s *ParseContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitParse(s)\n\t}\n}\n\nfunc (s *ParseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitParse(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Parse() (localctx IParseContext) {\n\tlocalctx = NewParseContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 0, ParserRULE_parse)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(229)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor ((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) {\n\t\t{\n\t\t\tp.SetState(226)\n\t\t\tp.Sql_stmt_list()\n\t\t}\n\n\t\tp.SetState(231)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\t{\n\t\tp.SetState(232)\n\t\tp.Match(ParserEOF)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISql_stmt_listContext is an interface to support dynamic dispatch.\ntype ISql_stmt_listContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAllSql_stmt() []ISql_stmtContext\n\tSql_stmt(i int) ISql_stmtContext\n\tAllSCOL() []antlr.TerminalNode\n\tSCOL(i int) antlr.TerminalNode\n\n\t// IsSql_stmt_listContext differentiates from other interfaces.\n\tIsSql_stmt_listContext()\n}\n\ntype Sql_stmt_listContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySql_stmt_listContext() *Sql_stmt_listContext {\n\tvar p = new(Sql_stmt_listContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_sql_stmt_list\n\treturn p\n}\n\nfunc InitEmptySql_stmt_listContext(p *Sql_stmt_listContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_sql_stmt_list\n}\n\nfunc (*Sql_stmt_listContext) IsSql_stmt_listContext() {}\n\nfunc NewSql_stmt_listContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Sql_stmt_listContext {\n\tvar p = new(Sql_stmt_listContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_sql_stmt_list\n\n\treturn p\n}\n\nfunc (s *Sql_stmt_listContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Sql_stmt_listContext) AllSql_stmt() []ISql_stmtContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ISql_stmtContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ISql_stmtContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ISql_stmtContext); ok {\n\t\t\ttst[i] = t.(ISql_stmtContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Sql_stmt_listContext) Sql_stmt(i int) ISql_stmtContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISql_stmtContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISql_stmtContext)\n}\n\nfunc (s *Sql_stmt_listContext) AllSCOL() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserSCOL)\n}\n\nfunc (s *Sql_stmt_listContext) SCOL(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserSCOL, i)\n}\n\nfunc (s *Sql_stmt_listContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Sql_stmt_listContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Sql_stmt_listContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSql_stmt_list(s)\n\t}\n}\n\nfunc (s *Sql_stmt_listContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSql_stmt_list(s)\n\t}\n}\n\nfunc (s *Sql_stmt_listContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSql_stmt_list(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Sql_stmt_list() (localctx ISql_stmt_listContext) {\n\tlocalctx = NewSql_stmt_listContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 2, ParserRULE_sql_stmt_list)\n\tvar _la int\n\n\tvar _alt int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(237)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserSCOL {\n\t\t{\n\t\t\tp.SetState(234)\n\t\t\tp.Match(ParserSCOL)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t\tp.SetState(239)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\t{\n\t\tp.SetState(240)\n\t\tp.Sql_stmt()\n\t}\n\tp.SetState(249)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 3, p.GetParserRuleContext())\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\tfor _alt != 2 && _alt != antlr.ATNInvalidAltNumber {\n\t\tif _alt == 1 {\n\t\t\tp.SetState(242)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor ok := true; ok; ok = _la == ParserSCOL {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(241)\n\t\t\t\t\tp.Match(ParserSCOL)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tp.SetState(244)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(246)\n\t\t\t\tp.Sql_stmt()\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(251)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 3, p.GetParserRuleContext())\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(255)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 4, p.GetParserRuleContext())\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\tfor _alt != 2 && _alt != antlr.ATNInvalidAltNumber {\n\t\tif _alt == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(252)\n\t\t\t\tp.Match(ParserSCOL)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(257)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 4, p.GetParserRuleContext())\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISql_stmtContext is an interface to support dynamic dispatch.\ntype ISql_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAlter_table_stmt() IAlter_table_stmtContext\n\tAnalyze_stmt() IAnalyze_stmtContext\n\tAttach_stmt() IAttach_stmtContext\n\tBegin_stmt() IBegin_stmtContext\n\tCommit_stmt() ICommit_stmtContext\n\tCreate_index_stmt() ICreate_index_stmtContext\n\tCreate_table_stmt() ICreate_table_stmtContext\n\tCreate_trigger_stmt() ICreate_trigger_stmtContext\n\tCreate_view_stmt() ICreate_view_stmtContext\n\tCreate_virtual_table_stmt() ICreate_virtual_table_stmtContext\n\tDelete_stmt() IDelete_stmtContext\n\tDelete_stmt_limited() IDelete_stmt_limitedContext\n\tDetach_stmt() IDetach_stmtContext\n\tDrop_stmt() IDrop_stmtContext\n\tInsert_stmt() IInsert_stmtContext\n\tPragma_stmt() IPragma_stmtContext\n\tReindex_stmt() IReindex_stmtContext\n\tRelease_stmt() IRelease_stmtContext\n\tRollback_stmt() IRollback_stmtContext\n\tSavepoint_stmt() ISavepoint_stmtContext\n\tSelect_stmt() ISelect_stmtContext\n\tUpdate_stmt() IUpdate_stmtContext\n\tUpdate_stmt_limited() IUpdate_stmt_limitedContext\n\tVacuum_stmt() IVacuum_stmtContext\n\tEXPLAIN_() antlr.TerminalNode\n\tQUERY_() antlr.TerminalNode\n\tPLAN_() antlr.TerminalNode\n\n\t// IsSql_stmtContext differentiates from other interfaces.\n\tIsSql_stmtContext()\n}\n\ntype Sql_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySql_stmtContext() *Sql_stmtContext {\n\tvar p = new(Sql_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_sql_stmt\n\treturn p\n}\n\nfunc InitEmptySql_stmtContext(p *Sql_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_sql_stmt\n}\n\nfunc (*Sql_stmtContext) IsSql_stmtContext() {}\n\nfunc NewSql_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Sql_stmtContext {\n\tvar p = new(Sql_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_sql_stmt\n\n\treturn p\n}\n\nfunc (s *Sql_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Sql_stmtContext) Alter_table_stmt() IAlter_table_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAlter_table_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAlter_table_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Analyze_stmt() IAnalyze_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAnalyze_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAnalyze_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Attach_stmt() IAttach_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAttach_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAttach_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Begin_stmt() IBegin_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IBegin_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IBegin_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Commit_stmt() ICommit_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICommit_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICommit_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Create_index_stmt() ICreate_index_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICreate_index_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICreate_index_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Create_table_stmt() ICreate_table_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICreate_table_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICreate_table_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Create_trigger_stmt() ICreate_trigger_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICreate_trigger_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICreate_trigger_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Create_view_stmt() ICreate_view_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICreate_view_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICreate_view_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Create_virtual_table_stmt() ICreate_virtual_table_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICreate_virtual_table_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICreate_virtual_table_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Delete_stmt() IDelete_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IDelete_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IDelete_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Delete_stmt_limited() IDelete_stmt_limitedContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IDelete_stmt_limitedContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IDelete_stmt_limitedContext)\n}\n\nfunc (s *Sql_stmtContext) Detach_stmt() IDetach_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IDetach_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IDetach_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Drop_stmt() IDrop_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IDrop_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IDrop_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Insert_stmt() IInsert_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IInsert_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IInsert_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Pragma_stmt() IPragma_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IPragma_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IPragma_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Reindex_stmt() IReindex_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IReindex_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IReindex_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Release_stmt() IRelease_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IRelease_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IRelease_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Rollback_stmt() IRollback_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IRollback_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IRollback_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Savepoint_stmt() ISavepoint_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISavepoint_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISavepoint_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Select_stmt() ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Update_stmt() IUpdate_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IUpdate_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IUpdate_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) Update_stmt_limited() IUpdate_stmt_limitedContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IUpdate_stmt_limitedContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IUpdate_stmt_limitedContext)\n}\n\nfunc (s *Sql_stmtContext) Vacuum_stmt() IVacuum_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IVacuum_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IVacuum_stmtContext)\n}\n\nfunc (s *Sql_stmtContext) EXPLAIN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXPLAIN_, 0)\n}\n\nfunc (s *Sql_stmtContext) QUERY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserQUERY_, 0)\n}\n\nfunc (s *Sql_stmtContext) PLAN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPLAN_, 0)\n}\n\nfunc (s *Sql_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Sql_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Sql_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSql_stmt(s)\n\t}\n}\n\nfunc (s *Sql_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSql_stmt(s)\n\t}\n}\n\nfunc (s *Sql_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSql_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Sql_stmt() (localctx ISql_stmtContext) {\n\tlocalctx = NewSql_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 4, ParserRULE_sql_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(263)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserEXPLAIN_ {\n\t\t{\n\t\t\tp.SetState(258)\n\t\t\tp.Match(ParserEXPLAIN_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(261)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserQUERY_ {\n\t\t\t{\n\t\t\t\tp.SetState(259)\n\t\t\t\tp.Match(ParserQUERY_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(260)\n\t\t\t\tp.Match(ParserPLAN_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t}\n\tp.SetState(289)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 7, p.GetParserRuleContext()) {\n\tcase 1:\n\t\t{\n\t\t\tp.SetState(265)\n\t\t\tp.Alter_table_stmt()\n\t\t}\n\n\tcase 2:\n\t\t{\n\t\t\tp.SetState(266)\n\t\t\tp.Analyze_stmt()\n\t\t}\n\n\tcase 3:\n\t\t{\n\t\t\tp.SetState(267)\n\t\t\tp.Attach_stmt()\n\t\t}\n\n\tcase 4:\n\t\t{\n\t\t\tp.SetState(268)\n\t\t\tp.Begin_stmt()\n\t\t}\n\n\tcase 5:\n\t\t{\n\t\t\tp.SetState(269)\n\t\t\tp.Commit_stmt()\n\t\t}\n\n\tcase 6:\n\t\t{\n\t\t\tp.SetState(270)\n\t\t\tp.Create_index_stmt()\n\t\t}\n\n\tcase 7:\n\t\t{\n\t\t\tp.SetState(271)\n\t\t\tp.Create_table_stmt()\n\t\t}\n\n\tcase 8:\n\t\t{\n\t\t\tp.SetState(272)\n\t\t\tp.Create_trigger_stmt()\n\t\t}\n\n\tcase 9:\n\t\t{\n\t\t\tp.SetState(273)\n\t\t\tp.Create_view_stmt()\n\t\t}\n\n\tcase 10:\n\t\t{\n\t\t\tp.SetState(274)\n\t\t\tp.Create_virtual_table_stmt()\n\t\t}\n\n\tcase 11:\n\t\t{\n\t\t\tp.SetState(275)\n\t\t\tp.Delete_stmt()\n\t\t}\n\n\tcase 12:\n\t\t{\n\t\t\tp.SetState(276)\n\t\t\tp.Delete_stmt_limited()\n\t\t}\n\n\tcase 13:\n\t\t{\n\t\t\tp.SetState(277)\n\t\t\tp.Detach_stmt()\n\t\t}\n\n\tcase 14:\n\t\t{\n\t\t\tp.SetState(278)\n\t\t\tp.Drop_stmt()\n\t\t}\n\n\tcase 15:\n\t\t{\n\t\t\tp.SetState(279)\n\t\t\tp.Insert_stmt()\n\t\t}\n\n\tcase 16:\n\t\t{\n\t\t\tp.SetState(280)\n\t\t\tp.Pragma_stmt()\n\t\t}\n\n\tcase 17:\n\t\t{\n\t\t\tp.SetState(281)\n\t\t\tp.Reindex_stmt()\n\t\t}\n\n\tcase 18:\n\t\t{\n\t\t\tp.SetState(282)\n\t\t\tp.Release_stmt()\n\t\t}\n\n\tcase 19:\n\t\t{\n\t\t\tp.SetState(283)\n\t\t\tp.Rollback_stmt()\n\t\t}\n\n\tcase 20:\n\t\t{\n\t\t\tp.SetState(284)\n\t\t\tp.Savepoint_stmt()\n\t\t}\n\n\tcase 21:\n\t\t{\n\t\t\tp.SetState(285)\n\t\t\tp.Select_stmt()\n\t\t}\n\n\tcase 22:\n\t\t{\n\t\t\tp.SetState(286)\n\t\t\tp.Update_stmt()\n\t\t}\n\n\tcase 23:\n\t\t{\n\t\t\tp.SetState(287)\n\t\t\tp.Update_stmt_limited()\n\t\t}\n\n\tcase 24:\n\t\t{\n\t\t\tp.SetState(288)\n\t\t\tp.Vacuum_stmt()\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IAlter_table_stmtContext is an interface to support dynamic dispatch.\ntype IAlter_table_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// GetNew_table_name returns the new_table_name rule contexts.\n\tGetNew_table_name() ITable_nameContext\n\n\t// GetOld_column_name returns the old_column_name rule contexts.\n\tGetOld_column_name() IColumn_nameContext\n\n\t// GetNew_column_name returns the new_column_name rule contexts.\n\tGetNew_column_name() IColumn_nameContext\n\n\t// SetNew_table_name sets the new_table_name rule contexts.\n\tSetNew_table_name(ITable_nameContext)\n\n\t// SetOld_column_name sets the old_column_name rule contexts.\n\tSetOld_column_name(IColumn_nameContext)\n\n\t// SetNew_column_name sets the new_column_name rule contexts.\n\tSetNew_column_name(IColumn_nameContext)\n\n\t// Getter signatures\n\tALTER_() antlr.TerminalNode\n\tTABLE_() antlr.TerminalNode\n\tAllTable_name() []ITable_nameContext\n\tTable_name(i int) ITable_nameContext\n\tRENAME_() antlr.TerminalNode\n\tADD_() antlr.TerminalNode\n\tColumn_def() IColumn_defContext\n\tDROP_() antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\tTO_() antlr.TerminalNode\n\tCOLUMN_() antlr.TerminalNode\n\n\t// IsAlter_table_stmtContext differentiates from other interfaces.\n\tIsAlter_table_stmtContext()\n}\n\ntype Alter_table_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser          antlr.Parser\n\tnew_table_name  ITable_nameContext\n\told_column_name IColumn_nameContext\n\tnew_column_name IColumn_nameContext\n}\n\nfunc NewEmptyAlter_table_stmtContext() *Alter_table_stmtContext {\n\tvar p = new(Alter_table_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_alter_table_stmt\n\treturn p\n}\n\nfunc InitEmptyAlter_table_stmtContext(p *Alter_table_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_alter_table_stmt\n}\n\nfunc (*Alter_table_stmtContext) IsAlter_table_stmtContext() {}\n\nfunc NewAlter_table_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Alter_table_stmtContext {\n\tvar p = new(Alter_table_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_alter_table_stmt\n\n\treturn p\n}\n\nfunc (s *Alter_table_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Alter_table_stmtContext) GetNew_table_name() ITable_nameContext { return s.new_table_name }\n\nfunc (s *Alter_table_stmtContext) GetOld_column_name() IColumn_nameContext { return s.old_column_name }\n\nfunc (s *Alter_table_stmtContext) GetNew_column_name() IColumn_nameContext { return s.new_column_name }\n\nfunc (s *Alter_table_stmtContext) SetNew_table_name(v ITable_nameContext) { s.new_table_name = v }\n\nfunc (s *Alter_table_stmtContext) SetOld_column_name(v IColumn_nameContext) { s.old_column_name = v }\n\nfunc (s *Alter_table_stmtContext) SetNew_column_name(v IColumn_nameContext) { s.new_column_name = v }\n\nfunc (s *Alter_table_stmtContext) ALTER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserALTER_, 0)\n}\n\nfunc (s *Alter_table_stmtContext) TABLE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTABLE_, 0)\n}\n\nfunc (s *Alter_table_stmtContext) AllTable_name() []ITable_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ITable_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ITable_nameContext); ok {\n\t\t\ttst[i] = t.(ITable_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Alter_table_stmtContext) Table_name(i int) ITable_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Alter_table_stmtContext) RENAME_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRENAME_, 0)\n}\n\nfunc (s *Alter_table_stmtContext) ADD_() antlr.TerminalNode {\n\treturn s.GetToken(ParserADD_, 0)\n}\n\nfunc (s *Alter_table_stmtContext) Column_def() IColumn_defContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_defContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_defContext)\n}\n\nfunc (s *Alter_table_stmtContext) DROP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDROP_, 0)\n}\n\nfunc (s *Alter_table_stmtContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Alter_table_stmtContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Alter_table_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Alter_table_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Alter_table_stmtContext) TO_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTO_, 0)\n}\n\nfunc (s *Alter_table_stmtContext) COLUMN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOLUMN_, 0)\n}\n\nfunc (s *Alter_table_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Alter_table_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Alter_table_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterAlter_table_stmt(s)\n\t}\n}\n\nfunc (s *Alter_table_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitAlter_table_stmt(s)\n\t}\n}\n\nfunc (s *Alter_table_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitAlter_table_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Alter_table_stmt() (localctx IAlter_table_stmtContext) {\n\tlocalctx = NewAlter_table_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 6, ParserRULE_alter_table_stmt)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(291)\n\t\tp.Match(ParserALTER_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(292)\n\t\tp.Match(ParserTABLE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(296)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 8, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(293)\n\t\t\tp.Schema_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(294)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(298)\n\t\tp.Table_name()\n\t}\n\tp.SetState(321)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserRENAME_:\n\t\t{\n\t\t\tp.SetState(299)\n\t\t\tp.Match(ParserRENAME_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(309)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 10, p.GetParserRuleContext()) {\n\t\tcase 1:\n\t\t\t{\n\t\t\t\tp.SetState(300)\n\t\t\t\tp.Match(ParserTO_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(301)\n\n\t\t\t\tvar _x = p.Table_name()\n\n\t\t\t\tlocalctx.(*Alter_table_stmtContext).new_table_name = _x\n\t\t\t}\n\n\t\tcase 2:\n\t\t\tp.SetState(303)\n\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 9, p.GetParserRuleContext()) == 1 {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(302)\n\t\t\t\t\tp.Match(ParserCOLUMN_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else if p.HasError() { // JIM\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(305)\n\n\t\t\t\tvar _x = p.Column_name()\n\n\t\t\t\tlocalctx.(*Alter_table_stmtContext).old_column_name = _x\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(306)\n\t\t\t\tp.Match(ParserTO_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(307)\n\n\t\t\t\tvar _x = p.Column_name()\n\n\t\t\t\tlocalctx.(*Alter_table_stmtContext).new_column_name = _x\n\t\t\t}\n\n\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\tgoto errorExit\n\t\t}\n\n\tcase ParserADD_:\n\t\t{\n\t\t\tp.SetState(311)\n\t\t\tp.Match(ParserADD_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(313)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 11, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(312)\n\t\t\t\tp.Match(ParserCOLUMN_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(315)\n\t\t\tp.Column_def()\n\t\t}\n\n\tcase ParserDROP_:\n\t\t{\n\t\t\tp.SetState(316)\n\t\t\tp.Match(ParserDROP_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(318)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 12, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(317)\n\t\t\t\tp.Match(ParserCOLUMN_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(320)\n\t\t\tp.Column_name()\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IAnalyze_stmtContext is an interface to support dynamic dispatch.\ntype IAnalyze_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tANALYZE_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tTable_or_index_name() ITable_or_index_nameContext\n\tDOT() antlr.TerminalNode\n\n\t// IsAnalyze_stmtContext differentiates from other interfaces.\n\tIsAnalyze_stmtContext()\n}\n\ntype Analyze_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyAnalyze_stmtContext() *Analyze_stmtContext {\n\tvar p = new(Analyze_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_analyze_stmt\n\treturn p\n}\n\nfunc InitEmptyAnalyze_stmtContext(p *Analyze_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_analyze_stmt\n}\n\nfunc (*Analyze_stmtContext) IsAnalyze_stmtContext() {}\n\nfunc NewAnalyze_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Analyze_stmtContext {\n\tvar p = new(Analyze_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_analyze_stmt\n\n\treturn p\n}\n\nfunc (s *Analyze_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Analyze_stmtContext) ANALYZE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserANALYZE_, 0)\n}\n\nfunc (s *Analyze_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Analyze_stmtContext) Table_or_index_name() ITable_or_index_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_or_index_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_or_index_nameContext)\n}\n\nfunc (s *Analyze_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Analyze_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Analyze_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Analyze_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterAnalyze_stmt(s)\n\t}\n}\n\nfunc (s *Analyze_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitAnalyze_stmt(s)\n\t}\n}\n\nfunc (s *Analyze_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitAnalyze_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Analyze_stmt() (localctx IAnalyze_stmtContext) {\n\tlocalctx = NewAnalyze_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 8, ParserRULE_analyze_stmt)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(323)\n\t\tp.Match(ParserANALYZE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(331)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 15, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(324)\n\t\t\tp.Schema_name()\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t} else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 15, p.GetParserRuleContext()) == 2 {\n\t\tp.SetState(328)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 14, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(325)\n\t\t\t\tp.Schema_name()\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(326)\n\t\t\t\tp.Match(ParserDOT)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(330)\n\t\t\tp.Table_or_index_name()\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IAttach_stmtContext is an interface to support dynamic dispatch.\ntype IAttach_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tATTACH_() antlr.TerminalNode\n\tExpr() IExprContext\n\tAS_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tDATABASE_() antlr.TerminalNode\n\n\t// IsAttach_stmtContext differentiates from other interfaces.\n\tIsAttach_stmtContext()\n}\n\ntype Attach_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyAttach_stmtContext() *Attach_stmtContext {\n\tvar p = new(Attach_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_attach_stmt\n\treturn p\n}\n\nfunc InitEmptyAttach_stmtContext(p *Attach_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_attach_stmt\n}\n\nfunc (*Attach_stmtContext) IsAttach_stmtContext() {}\n\nfunc NewAttach_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Attach_stmtContext {\n\tvar p = new(Attach_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_attach_stmt\n\n\treturn p\n}\n\nfunc (s *Attach_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Attach_stmtContext) ATTACH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserATTACH_, 0)\n}\n\nfunc (s *Attach_stmtContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Attach_stmtContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *Attach_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Attach_stmtContext) DATABASE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDATABASE_, 0)\n}\n\nfunc (s *Attach_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Attach_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Attach_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterAttach_stmt(s)\n\t}\n}\n\nfunc (s *Attach_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitAttach_stmt(s)\n\t}\n}\n\nfunc (s *Attach_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitAttach_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Attach_stmt() (localctx IAttach_stmtContext) {\n\tlocalctx = NewAttach_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 10, ParserRULE_attach_stmt)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(333)\n\t\tp.Match(ParserATTACH_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(335)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 16, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(334)\n\t\t\tp.Match(ParserDATABASE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(337)\n\t\tp.expr(0)\n\t}\n\t{\n\t\tp.SetState(338)\n\t\tp.Match(ParserAS_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(339)\n\t\tp.Schema_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IBegin_stmtContext is an interface to support dynamic dispatch.\ntype IBegin_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tBEGIN_() antlr.TerminalNode\n\tTRANSACTION_() antlr.TerminalNode\n\tDEFERRED_() antlr.TerminalNode\n\tIMMEDIATE_() antlr.TerminalNode\n\tEXCLUSIVE_() antlr.TerminalNode\n\tTransaction_name() ITransaction_nameContext\n\n\t// IsBegin_stmtContext differentiates from other interfaces.\n\tIsBegin_stmtContext()\n}\n\ntype Begin_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyBegin_stmtContext() *Begin_stmtContext {\n\tvar p = new(Begin_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_begin_stmt\n\treturn p\n}\n\nfunc InitEmptyBegin_stmtContext(p *Begin_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_begin_stmt\n}\n\nfunc (*Begin_stmtContext) IsBegin_stmtContext() {}\n\nfunc NewBegin_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Begin_stmtContext {\n\tvar p = new(Begin_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_begin_stmt\n\n\treturn p\n}\n\nfunc (s *Begin_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Begin_stmtContext) BEGIN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBEGIN_, 0)\n}\n\nfunc (s *Begin_stmtContext) TRANSACTION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTRANSACTION_, 0)\n}\n\nfunc (s *Begin_stmtContext) DEFERRED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDEFERRED_, 0)\n}\n\nfunc (s *Begin_stmtContext) IMMEDIATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIMMEDIATE_, 0)\n}\n\nfunc (s *Begin_stmtContext) EXCLUSIVE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXCLUSIVE_, 0)\n}\n\nfunc (s *Begin_stmtContext) Transaction_name() ITransaction_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITransaction_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITransaction_nameContext)\n}\n\nfunc (s *Begin_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Begin_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Begin_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterBegin_stmt(s)\n\t}\n}\n\nfunc (s *Begin_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitBegin_stmt(s)\n\t}\n}\n\nfunc (s *Begin_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitBegin_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Begin_stmt() (localctx IBegin_stmtContext) {\n\tlocalctx = NewBegin_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 12, ParserRULE_begin_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(341)\n\t\tp.Match(ParserBEGIN_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(343)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif (int64((_la-58)) & ^0x3f) == 0 && ((int64(1)<<(_la-58))&16779265) != 0 {\n\t\t{\n\t\t\tp.SetState(342)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !((int64((_la-58)) & ^0x3f) == 0 && ((int64(1)<<(_la-58))&16779265) != 0) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\n\t}\n\tp.SetState(349)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserTRANSACTION_ {\n\t\t{\n\t\t\tp.SetState(345)\n\t\t\tp.Match(ParserTRANSACTION_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(347)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 18, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(346)\n\t\t\t\tp.Transaction_name()\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICommit_stmtContext is an interface to support dynamic dispatch.\ntype ICommit_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tCOMMIT_() antlr.TerminalNode\n\tEND_() antlr.TerminalNode\n\tTRANSACTION_() antlr.TerminalNode\n\n\t// IsCommit_stmtContext differentiates from other interfaces.\n\tIsCommit_stmtContext()\n}\n\ntype Commit_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCommit_stmtContext() *Commit_stmtContext {\n\tvar p = new(Commit_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_commit_stmt\n\treturn p\n}\n\nfunc InitEmptyCommit_stmtContext(p *Commit_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_commit_stmt\n}\n\nfunc (*Commit_stmtContext) IsCommit_stmtContext() {}\n\nfunc NewCommit_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Commit_stmtContext {\n\tvar p = new(Commit_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_commit_stmt\n\n\treturn p\n}\n\nfunc (s *Commit_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Commit_stmtContext) COMMIT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMIT_, 0)\n}\n\nfunc (s *Commit_stmtContext) END_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEND_, 0)\n}\n\nfunc (s *Commit_stmtContext) TRANSACTION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTRANSACTION_, 0)\n}\n\nfunc (s *Commit_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Commit_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Commit_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCommit_stmt(s)\n\t}\n}\n\nfunc (s *Commit_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCommit_stmt(s)\n\t}\n}\n\nfunc (s *Commit_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCommit_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Commit_stmt() (localctx ICommit_stmtContext) {\n\tlocalctx = NewCommit_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 14, ParserRULE_commit_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(351)\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif !(_la == ParserCOMMIT_ || _la == ParserEND_) {\n\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t} else {\n\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\tp.Consume()\n\t\t}\n\t}\n\tp.SetState(353)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserTRANSACTION_ {\n\t\t{\n\t\t\tp.SetState(352)\n\t\t\tp.Match(ParserTRANSACTION_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IRollback_stmtContext is an interface to support dynamic dispatch.\ntype IRollback_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tROLLBACK_() antlr.TerminalNode\n\tTRANSACTION_() antlr.TerminalNode\n\tTO_() antlr.TerminalNode\n\tSavepoint_name() ISavepoint_nameContext\n\tSAVEPOINT_() antlr.TerminalNode\n\n\t// IsRollback_stmtContext differentiates from other interfaces.\n\tIsRollback_stmtContext()\n}\n\ntype Rollback_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyRollback_stmtContext() *Rollback_stmtContext {\n\tvar p = new(Rollback_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_rollback_stmt\n\treturn p\n}\n\nfunc InitEmptyRollback_stmtContext(p *Rollback_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_rollback_stmt\n}\n\nfunc (*Rollback_stmtContext) IsRollback_stmtContext() {}\n\nfunc NewRollback_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Rollback_stmtContext {\n\tvar p = new(Rollback_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_rollback_stmt\n\n\treturn p\n}\n\nfunc (s *Rollback_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Rollback_stmtContext) ROLLBACK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROLLBACK_, 0)\n}\n\nfunc (s *Rollback_stmtContext) TRANSACTION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTRANSACTION_, 0)\n}\n\nfunc (s *Rollback_stmtContext) TO_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTO_, 0)\n}\n\nfunc (s *Rollback_stmtContext) Savepoint_name() ISavepoint_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISavepoint_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISavepoint_nameContext)\n}\n\nfunc (s *Rollback_stmtContext) SAVEPOINT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSAVEPOINT_, 0)\n}\n\nfunc (s *Rollback_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Rollback_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Rollback_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterRollback_stmt(s)\n\t}\n}\n\nfunc (s *Rollback_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitRollback_stmt(s)\n\t}\n}\n\nfunc (s *Rollback_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitRollback_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Rollback_stmt() (localctx IRollback_stmtContext) {\n\tlocalctx = NewRollback_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 16, ParserRULE_rollback_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(355)\n\t\tp.Match(ParserROLLBACK_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(357)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserTRANSACTION_ {\n\t\t{\n\t\t\tp.SetState(356)\n\t\t\tp.Match(ParserTRANSACTION_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\tp.SetState(364)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserTO_ {\n\t\t{\n\t\t\tp.SetState(359)\n\t\t\tp.Match(ParserTO_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(361)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 22, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(360)\n\t\t\t\tp.Match(ParserSAVEPOINT_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(363)\n\t\t\tp.Savepoint_name()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISavepoint_stmtContext is an interface to support dynamic dispatch.\ntype ISavepoint_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tSAVEPOINT_() antlr.TerminalNode\n\tSavepoint_name() ISavepoint_nameContext\n\n\t// IsSavepoint_stmtContext differentiates from other interfaces.\n\tIsSavepoint_stmtContext()\n}\n\ntype Savepoint_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySavepoint_stmtContext() *Savepoint_stmtContext {\n\tvar p = new(Savepoint_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_savepoint_stmt\n\treturn p\n}\n\nfunc InitEmptySavepoint_stmtContext(p *Savepoint_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_savepoint_stmt\n}\n\nfunc (*Savepoint_stmtContext) IsSavepoint_stmtContext() {}\n\nfunc NewSavepoint_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Savepoint_stmtContext {\n\tvar p = new(Savepoint_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_savepoint_stmt\n\n\treturn p\n}\n\nfunc (s *Savepoint_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Savepoint_stmtContext) SAVEPOINT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSAVEPOINT_, 0)\n}\n\nfunc (s *Savepoint_stmtContext) Savepoint_name() ISavepoint_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISavepoint_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISavepoint_nameContext)\n}\n\nfunc (s *Savepoint_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Savepoint_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Savepoint_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSavepoint_stmt(s)\n\t}\n}\n\nfunc (s *Savepoint_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSavepoint_stmt(s)\n\t}\n}\n\nfunc (s *Savepoint_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSavepoint_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Savepoint_stmt() (localctx ISavepoint_stmtContext) {\n\tlocalctx = NewSavepoint_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 18, ParserRULE_savepoint_stmt)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(366)\n\t\tp.Match(ParserSAVEPOINT_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(367)\n\t\tp.Savepoint_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IRelease_stmtContext is an interface to support dynamic dispatch.\ntype IRelease_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tRELEASE_() antlr.TerminalNode\n\tSavepoint_name() ISavepoint_nameContext\n\tSAVEPOINT_() antlr.TerminalNode\n\n\t// IsRelease_stmtContext differentiates from other interfaces.\n\tIsRelease_stmtContext()\n}\n\ntype Release_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyRelease_stmtContext() *Release_stmtContext {\n\tvar p = new(Release_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_release_stmt\n\treturn p\n}\n\nfunc InitEmptyRelease_stmtContext(p *Release_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_release_stmt\n}\n\nfunc (*Release_stmtContext) IsRelease_stmtContext() {}\n\nfunc NewRelease_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Release_stmtContext {\n\tvar p = new(Release_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_release_stmt\n\n\treturn p\n}\n\nfunc (s *Release_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Release_stmtContext) RELEASE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRELEASE_, 0)\n}\n\nfunc (s *Release_stmtContext) Savepoint_name() ISavepoint_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISavepoint_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISavepoint_nameContext)\n}\n\nfunc (s *Release_stmtContext) SAVEPOINT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSAVEPOINT_, 0)\n}\n\nfunc (s *Release_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Release_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Release_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterRelease_stmt(s)\n\t}\n}\n\nfunc (s *Release_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitRelease_stmt(s)\n\t}\n}\n\nfunc (s *Release_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitRelease_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Release_stmt() (localctx IRelease_stmtContext) {\n\tlocalctx = NewRelease_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 20, ParserRULE_release_stmt)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(369)\n\t\tp.Match(ParserRELEASE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(371)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 24, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(370)\n\t\t\tp.Match(ParserSAVEPOINT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(373)\n\t\tp.Savepoint_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICreate_index_stmtContext is an interface to support dynamic dispatch.\ntype ICreate_index_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tCREATE_() antlr.TerminalNode\n\tINDEX_() antlr.TerminalNode\n\tIndex_name() IIndex_nameContext\n\tON_() antlr.TerminalNode\n\tTable_name() ITable_nameContext\n\tOPEN_PAR() antlr.TerminalNode\n\tAllIndexed_column() []IIndexed_columnContext\n\tIndexed_column(i int) IIndexed_columnContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tUNIQUE_() antlr.TerminalNode\n\tIF_() antlr.TerminalNode\n\tNOT_() antlr.TerminalNode\n\tEXISTS_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\tWHERE_() antlr.TerminalNode\n\tExpr() IExprContext\n\n\t// IsCreate_index_stmtContext differentiates from other interfaces.\n\tIsCreate_index_stmtContext()\n}\n\ntype Create_index_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCreate_index_stmtContext() *Create_index_stmtContext {\n\tvar p = new(Create_index_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_create_index_stmt\n\treturn p\n}\n\nfunc InitEmptyCreate_index_stmtContext(p *Create_index_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_create_index_stmt\n}\n\nfunc (*Create_index_stmtContext) IsCreate_index_stmtContext() {}\n\nfunc NewCreate_index_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Create_index_stmtContext {\n\tvar p = new(Create_index_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_create_index_stmt\n\n\treturn p\n}\n\nfunc (s *Create_index_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Create_index_stmtContext) CREATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCREATE_, 0)\n}\n\nfunc (s *Create_index_stmtContext) INDEX_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINDEX_, 0)\n}\n\nfunc (s *Create_index_stmtContext) Index_name() IIndex_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IIndex_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IIndex_nameContext)\n}\n\nfunc (s *Create_index_stmtContext) ON_() antlr.TerminalNode {\n\treturn s.GetToken(ParserON_, 0)\n}\n\nfunc (s *Create_index_stmtContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Create_index_stmtContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Create_index_stmtContext) AllIndexed_column() []IIndexed_columnContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IIndexed_columnContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IIndexed_columnContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IIndexed_columnContext); ok {\n\t\t\ttst[i] = t.(IIndexed_columnContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Create_index_stmtContext) Indexed_column(i int) IIndexed_columnContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IIndexed_columnContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IIndexed_columnContext)\n}\n\nfunc (s *Create_index_stmtContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Create_index_stmtContext) UNIQUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNIQUE_, 0)\n}\n\nfunc (s *Create_index_stmtContext) IF_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIF_, 0)\n}\n\nfunc (s *Create_index_stmtContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *Create_index_stmtContext) EXISTS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXISTS_, 0)\n}\n\nfunc (s *Create_index_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Create_index_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Create_index_stmtContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Create_index_stmtContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Create_index_stmtContext) WHERE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWHERE_, 0)\n}\n\nfunc (s *Create_index_stmtContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Create_index_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Create_index_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Create_index_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCreate_index_stmt(s)\n\t}\n}\n\nfunc (s *Create_index_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCreate_index_stmt(s)\n\t}\n}\n\nfunc (s *Create_index_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCreate_index_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Create_index_stmt() (localctx ICreate_index_stmtContext) {\n\tlocalctx = NewCreate_index_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 22, ParserRULE_create_index_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(375)\n\t\tp.Match(ParserCREATE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(377)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserUNIQUE_ {\n\t\t{\n\t\t\tp.SetState(376)\n\t\t\tp.Match(ParserUNIQUE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(379)\n\t\tp.Match(ParserINDEX_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(383)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 26, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(380)\n\t\t\tp.Match(ParserIF_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(381)\n\t\t\tp.Match(ParserNOT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(382)\n\t\t\tp.Match(ParserEXISTS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\tp.SetState(388)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 27, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(385)\n\t\t\tp.Schema_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(386)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(390)\n\t\tp.Index_name()\n\t}\n\t{\n\t\tp.SetState(391)\n\t\tp.Match(ParserON_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(392)\n\t\tp.Table_name()\n\t}\n\t{\n\t\tp.SetState(393)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(394)\n\t\tp.Indexed_column()\n\t}\n\tp.SetState(399)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA {\n\t\t{\n\t\t\tp.SetState(395)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(396)\n\t\t\tp.Indexed_column()\n\t\t}\n\n\t\tp.SetState(401)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\t{\n\t\tp.SetState(402)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(405)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWHERE_ {\n\t\t{\n\t\t\tp.SetState(403)\n\t\t\tp.Match(ParserWHERE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(404)\n\t\t\tp.expr(0)\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IIndexed_columnContext is an interface to support dynamic dispatch.\ntype IIndexed_columnContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tColumn_name() IColumn_nameContext\n\tExpr() IExprContext\n\tCOLLATE_() antlr.TerminalNode\n\tCollation_name() ICollation_nameContext\n\tAsc_desc() IAsc_descContext\n\n\t// IsIndexed_columnContext differentiates from other interfaces.\n\tIsIndexed_columnContext()\n}\n\ntype Indexed_columnContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyIndexed_columnContext() *Indexed_columnContext {\n\tvar p = new(Indexed_columnContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_indexed_column\n\treturn p\n}\n\nfunc InitEmptyIndexed_columnContext(p *Indexed_columnContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_indexed_column\n}\n\nfunc (*Indexed_columnContext) IsIndexed_columnContext() {}\n\nfunc NewIndexed_columnContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Indexed_columnContext {\n\tvar p = new(Indexed_columnContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_indexed_column\n\n\treturn p\n}\n\nfunc (s *Indexed_columnContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Indexed_columnContext) Column_name() IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Indexed_columnContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Indexed_columnContext) COLLATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOLLATE_, 0)\n}\n\nfunc (s *Indexed_columnContext) Collation_name() ICollation_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICollation_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICollation_nameContext)\n}\n\nfunc (s *Indexed_columnContext) Asc_desc() IAsc_descContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAsc_descContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAsc_descContext)\n}\n\nfunc (s *Indexed_columnContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Indexed_columnContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Indexed_columnContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterIndexed_column(s)\n\t}\n}\n\nfunc (s *Indexed_columnContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitIndexed_column(s)\n\t}\n}\n\nfunc (s *Indexed_columnContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitIndexed_column(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Indexed_column() (localctx IIndexed_columnContext) {\n\tlocalctx = NewIndexed_columnContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 24, ParserRULE_indexed_column)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(409)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 30, p.GetParserRuleContext()) {\n\tcase 1:\n\t\t{\n\t\t\tp.SetState(407)\n\t\t\tp.Column_name()\n\t\t}\n\n\tcase 2:\n\t\t{\n\t\t\tp.SetState(408)\n\t\t\tp.expr(0)\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\tp.SetState(413)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserCOLLATE_ {\n\t\t{\n\t\t\tp.SetState(411)\n\t\t\tp.Match(ParserCOLLATE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(412)\n\t\t\tp.Collation_name()\n\t\t}\n\n\t}\n\tp.SetState(416)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserASC_ || _la == ParserDESC_ {\n\t\t{\n\t\t\tp.SetState(415)\n\t\t\tp.Asc_desc()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICreate_table_stmtContext is an interface to support dynamic dispatch.\ntype ICreate_table_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// GetRow_ROW_ID returns the row_ROW_ID token.\n\tGetRow_ROW_ID() antlr.Token\n\n\t// SetRow_ROW_ID sets the row_ROW_ID token.\n\tSetRow_ROW_ID(antlr.Token)\n\n\t// Getter signatures\n\tCREATE_() antlr.TerminalNode\n\tTABLE_() antlr.TerminalNode\n\tTable_name() ITable_nameContext\n\tOPEN_PAR() antlr.TerminalNode\n\tAllColumn_def() []IColumn_defContext\n\tColumn_def(i int) IColumn_defContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tAS_() antlr.TerminalNode\n\tSelect_stmt() ISelect_stmtContext\n\tIF_() antlr.TerminalNode\n\tNOT_() antlr.TerminalNode\n\tEXISTS_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\tTEMP_() antlr.TerminalNode\n\tTEMPORARY_() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\tAllTable_constraint() []ITable_constraintContext\n\tTable_constraint(i int) ITable_constraintContext\n\tWITHOUT_() antlr.TerminalNode\n\tIDENTIFIER() antlr.TerminalNode\n\n\t// IsCreate_table_stmtContext differentiates from other interfaces.\n\tIsCreate_table_stmtContext()\n}\n\ntype Create_table_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser     antlr.Parser\n\trow_ROW_ID antlr.Token\n}\n\nfunc NewEmptyCreate_table_stmtContext() *Create_table_stmtContext {\n\tvar p = new(Create_table_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_create_table_stmt\n\treturn p\n}\n\nfunc InitEmptyCreate_table_stmtContext(p *Create_table_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_create_table_stmt\n}\n\nfunc (*Create_table_stmtContext) IsCreate_table_stmtContext() {}\n\nfunc NewCreate_table_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Create_table_stmtContext {\n\tvar p = new(Create_table_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_create_table_stmt\n\n\treturn p\n}\n\nfunc (s *Create_table_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Create_table_stmtContext) GetRow_ROW_ID() antlr.Token { return s.row_ROW_ID }\n\nfunc (s *Create_table_stmtContext) SetRow_ROW_ID(v antlr.Token) { s.row_ROW_ID = v }\n\nfunc (s *Create_table_stmtContext) CREATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCREATE_, 0)\n}\n\nfunc (s *Create_table_stmtContext) TABLE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTABLE_, 0)\n}\n\nfunc (s *Create_table_stmtContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Create_table_stmtContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Create_table_stmtContext) AllColumn_def() []IColumn_defContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_defContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_defContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_defContext); ok {\n\t\t\ttst[i] = t.(IColumn_defContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Create_table_stmtContext) Column_def(i int) IColumn_defContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_defContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_defContext)\n}\n\nfunc (s *Create_table_stmtContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Create_table_stmtContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *Create_table_stmtContext) Select_stmt() ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *Create_table_stmtContext) IF_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIF_, 0)\n}\n\nfunc (s *Create_table_stmtContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *Create_table_stmtContext) EXISTS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXISTS_, 0)\n}\n\nfunc (s *Create_table_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Create_table_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Create_table_stmtContext) TEMP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTEMP_, 0)\n}\n\nfunc (s *Create_table_stmtContext) TEMPORARY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTEMPORARY_, 0)\n}\n\nfunc (s *Create_table_stmtContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Create_table_stmtContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Create_table_stmtContext) AllTable_constraint() []ITable_constraintContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ITable_constraintContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ITable_constraintContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ITable_constraintContext); ok {\n\t\t\ttst[i] = t.(ITable_constraintContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Create_table_stmtContext) Table_constraint(i int) ITable_constraintContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_constraintContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_constraintContext)\n}\n\nfunc (s *Create_table_stmtContext) WITHOUT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWITHOUT_, 0)\n}\n\nfunc (s *Create_table_stmtContext) IDENTIFIER() antlr.TerminalNode {\n\treturn s.GetToken(ParserIDENTIFIER, 0)\n}\n\nfunc (s *Create_table_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Create_table_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Create_table_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCreate_table_stmt(s)\n\t}\n}\n\nfunc (s *Create_table_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCreate_table_stmt(s)\n\t}\n}\n\nfunc (s *Create_table_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCreate_table_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Create_table_stmt() (localctx ICreate_table_stmtContext) {\n\tlocalctx = NewCreate_table_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 26, ParserRULE_create_table_stmt)\n\tvar _la int\n\n\tvar _alt int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(418)\n\t\tp.Match(ParserCREATE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(420)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserTEMP_ || _la == ParserTEMPORARY_ {\n\t\t{\n\t\t\tp.SetState(419)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserTEMP_ || _la == ParserTEMPORARY_) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(422)\n\t\tp.Match(ParserTABLE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(426)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 34, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(423)\n\t\t\tp.Match(ParserIF_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(424)\n\t\t\tp.Match(ParserNOT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(425)\n\t\t\tp.Match(ParserEXISTS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\tp.SetState(431)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 35, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(428)\n\t\t\tp.Schema_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(429)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(433)\n\t\tp.Table_name()\n\t}\n\tp.SetState(457)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserOPEN_PAR:\n\t\t{\n\t\t\tp.SetState(434)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(435)\n\t\t\tp.Column_def()\n\t\t}\n\t\tp.SetState(440)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 36, p.GetParserRuleContext())\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\tfor _alt != 1 && _alt != antlr.ATNInvalidAltNumber {\n\t\t\tif _alt == 1+1 {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(436)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(437)\n\t\t\t\t\tp.Column_def()\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tp.SetState(442)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 36, p.GetParserRuleContext())\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(447)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(443)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(444)\n\t\t\t\tp.Table_constraint()\n\t\t\t}\n\n\t\t\tp.SetState(449)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(450)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(453)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserWITHOUT_ {\n\t\t\t{\n\t\t\t\tp.SetState(451)\n\t\t\t\tp.Match(ParserWITHOUT_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(452)\n\n\t\t\t\tvar _m = p.Match(ParserIDENTIFIER)\n\n\t\t\t\tlocalctx.(*Create_table_stmtContext).row_ROW_ID = _m\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tcase ParserAS_:\n\t\t{\n\t\t\tp.SetState(455)\n\t\t\tp.Match(ParserAS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(456)\n\t\t\tp.Select_stmt()\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IColumn_defContext is an interface to support dynamic dispatch.\ntype IColumn_defContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tColumn_name() IColumn_nameContext\n\tType_name() IType_nameContext\n\tAllColumn_constraint() []IColumn_constraintContext\n\tColumn_constraint(i int) IColumn_constraintContext\n\n\t// IsColumn_defContext differentiates from other interfaces.\n\tIsColumn_defContext()\n}\n\ntype Column_defContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyColumn_defContext() *Column_defContext {\n\tvar p = new(Column_defContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_column_def\n\treturn p\n}\n\nfunc InitEmptyColumn_defContext(p *Column_defContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_column_def\n}\n\nfunc (*Column_defContext) IsColumn_defContext() {}\n\nfunc NewColumn_defContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Column_defContext {\n\tvar p = new(Column_defContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_column_def\n\n\treturn p\n}\n\nfunc (s *Column_defContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Column_defContext) Column_name() IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Column_defContext) Type_name() IType_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IType_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IType_nameContext)\n}\n\nfunc (s *Column_defContext) AllColumn_constraint() []IColumn_constraintContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_constraintContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_constraintContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_constraintContext); ok {\n\t\t\ttst[i] = t.(IColumn_constraintContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Column_defContext) Column_constraint(i int) IColumn_constraintContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_constraintContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_constraintContext)\n}\n\nfunc (s *Column_defContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Column_defContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Column_defContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterColumn_def(s)\n\t}\n}\n\nfunc (s *Column_defContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitColumn_def(s)\n\t}\n}\n\nfunc (s *Column_defContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitColumn_def(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Column_def() (localctx IColumn_defContext) {\n\tlocalctx = NewColumn_defContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 28, ParserRULE_column_def)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(459)\n\t\tp.Column_name()\n\t}\n\tp.SetState(461)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 40, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(460)\n\t\t\tp.Type_name()\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\tp.SetState(466)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor ((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&72673329139417088) != 0) || ((int64((_la-102)) & ^0x3f) == 0 && ((int64(1)<<(_la-102))&274877941761) != 0) || _la == ParserGENERATED_ {\n\t\t{\n\t\t\tp.SetState(463)\n\t\t\tp.Column_constraint()\n\t\t}\n\n\t\tp.SetState(468)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IType_nameContext is an interface to support dynamic dispatch.\ntype IType_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAllName() []INameContext\n\tName(i int) INameContext\n\tOPEN_PAR() antlr.TerminalNode\n\tAllSigned_number() []ISigned_numberContext\n\tSigned_number(i int) ISigned_numberContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tCOMMA() antlr.TerminalNode\n\n\t// IsType_nameContext differentiates from other interfaces.\n\tIsType_nameContext()\n}\n\ntype Type_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyType_nameContext() *Type_nameContext {\n\tvar p = new(Type_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_type_name\n\treturn p\n}\n\nfunc InitEmptyType_nameContext(p *Type_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_type_name\n}\n\nfunc (*Type_nameContext) IsType_nameContext() {}\n\nfunc NewType_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Type_nameContext {\n\tvar p = new(Type_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_type_name\n\n\treturn p\n}\n\nfunc (s *Type_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Type_nameContext) AllName() []INameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(INameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]INameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(INameContext); ok {\n\t\t\ttst[i] = t.(INameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Type_nameContext) Name(i int) INameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(INameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(INameContext)\n}\n\nfunc (s *Type_nameContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Type_nameContext) AllSigned_number() []ISigned_numberContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ISigned_numberContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ISigned_numberContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ISigned_numberContext); ok {\n\t\t\ttst[i] = t.(ISigned_numberContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Type_nameContext) Signed_number(i int) ISigned_numberContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISigned_numberContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISigned_numberContext)\n}\n\nfunc (s *Type_nameContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Type_nameContext) COMMA() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, 0)\n}\n\nfunc (s *Type_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Type_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Type_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterType_name(s)\n\t}\n}\n\nfunc (s *Type_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitType_name(s)\n\t}\n}\n\nfunc (s *Type_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitType_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Type_name() (localctx IType_nameContext) {\n\tlocalctx = NewType_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 30, ParserRULE_type_name)\n\tvar _alt int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(470)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_alt = 1 + 1\n\tfor ok := true; ok; ok = _alt != 1 && _alt != antlr.ATNInvalidAltNumber {\n\t\tswitch _alt {\n\t\tcase 1 + 1:\n\t\t\t{\n\t\t\t\tp.SetState(469)\n\t\t\t\tp.Name()\n\t\t\t}\n\n\t\tdefault:\n\t\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tp.SetState(472)\n\t\tp.GetErrorHandler().Sync(p)\n\t\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 42, p.GetParserRuleContext())\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(484)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 43, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(474)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(475)\n\t\t\tp.Signed_number()\n\t\t}\n\t\t{\n\t\t\tp.SetState(476)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t} else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 43, p.GetParserRuleContext()) == 2 {\n\t\t{\n\t\t\tp.SetState(478)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(479)\n\t\t\tp.Signed_number()\n\t\t}\n\t\t{\n\t\t\tp.SetState(480)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(481)\n\t\t\tp.Signed_number()\n\t\t}\n\t\t{\n\t\t\tp.SetState(482)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IColumn_constraintContext is an interface to support dynamic dispatch.\ntype IColumn_constraintContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tCHECK_() antlr.TerminalNode\n\tOPEN_PAR() antlr.TerminalNode\n\tExpr() IExprContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tDEFAULT_() antlr.TerminalNode\n\tCOLLATE_() antlr.TerminalNode\n\tCollation_name() ICollation_nameContext\n\tForeign_key_clause() IForeign_key_clauseContext\n\tAS_() antlr.TerminalNode\n\tCONSTRAINT_() antlr.TerminalNode\n\tName() INameContext\n\tPRIMARY_() antlr.TerminalNode\n\tKEY_() antlr.TerminalNode\n\tNOT_() antlr.TerminalNode\n\tNULL_() antlr.TerminalNode\n\tUNIQUE_() antlr.TerminalNode\n\tSigned_number() ISigned_numberContext\n\tLiteral_value() ILiteral_valueContext\n\tConflict_clause() IConflict_clauseContext\n\tGENERATED_() antlr.TerminalNode\n\tALWAYS_() antlr.TerminalNode\n\tSTORED_() antlr.TerminalNode\n\tVIRTUAL_() antlr.TerminalNode\n\tAsc_desc() IAsc_descContext\n\tAUTOINCREMENT_() antlr.TerminalNode\n\n\t// IsColumn_constraintContext differentiates from other interfaces.\n\tIsColumn_constraintContext()\n}\n\ntype Column_constraintContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyColumn_constraintContext() *Column_constraintContext {\n\tvar p = new(Column_constraintContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_column_constraint\n\treturn p\n}\n\nfunc InitEmptyColumn_constraintContext(p *Column_constraintContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_column_constraint\n}\n\nfunc (*Column_constraintContext) IsColumn_constraintContext() {}\n\nfunc NewColumn_constraintContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Column_constraintContext {\n\tvar p = new(Column_constraintContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_column_constraint\n\n\treturn p\n}\n\nfunc (s *Column_constraintContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Column_constraintContext) CHECK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCHECK_, 0)\n}\n\nfunc (s *Column_constraintContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Column_constraintContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Column_constraintContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Column_constraintContext) DEFAULT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDEFAULT_, 0)\n}\n\nfunc (s *Column_constraintContext) COLLATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOLLATE_, 0)\n}\n\nfunc (s *Column_constraintContext) Collation_name() ICollation_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICollation_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICollation_nameContext)\n}\n\nfunc (s *Column_constraintContext) Foreign_key_clause() IForeign_key_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IForeign_key_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IForeign_key_clauseContext)\n}\n\nfunc (s *Column_constraintContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *Column_constraintContext) CONSTRAINT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCONSTRAINT_, 0)\n}\n\nfunc (s *Column_constraintContext) Name() INameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(INameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(INameContext)\n}\n\nfunc (s *Column_constraintContext) PRIMARY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPRIMARY_, 0)\n}\n\nfunc (s *Column_constraintContext) KEY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserKEY_, 0)\n}\n\nfunc (s *Column_constraintContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *Column_constraintContext) NULL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNULL_, 0)\n}\n\nfunc (s *Column_constraintContext) UNIQUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNIQUE_, 0)\n}\n\nfunc (s *Column_constraintContext) Signed_number() ISigned_numberContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISigned_numberContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISigned_numberContext)\n}\n\nfunc (s *Column_constraintContext) Literal_value() ILiteral_valueContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ILiteral_valueContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ILiteral_valueContext)\n}\n\nfunc (s *Column_constraintContext) Conflict_clause() IConflict_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IConflict_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IConflict_clauseContext)\n}\n\nfunc (s *Column_constraintContext) GENERATED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserGENERATED_, 0)\n}\n\nfunc (s *Column_constraintContext) ALWAYS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserALWAYS_, 0)\n}\n\nfunc (s *Column_constraintContext) STORED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTORED_, 0)\n}\n\nfunc (s *Column_constraintContext) VIRTUAL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVIRTUAL_, 0)\n}\n\nfunc (s *Column_constraintContext) Asc_desc() IAsc_descContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAsc_descContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAsc_descContext)\n}\n\nfunc (s *Column_constraintContext) AUTOINCREMENT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAUTOINCREMENT_, 0)\n}\n\nfunc (s *Column_constraintContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Column_constraintContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Column_constraintContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterColumn_constraint(s)\n\t}\n}\n\nfunc (s *Column_constraintContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitColumn_constraint(s)\n\t}\n}\n\nfunc (s *Column_constraintContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitColumn_constraint(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Column_constraint() (localctx IColumn_constraintContext) {\n\tlocalctx = NewColumn_constraintContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 32, ParserRULE_column_constraint)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(488)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserCONSTRAINT_ {\n\t\t{\n\t\t\tp.SetState(486)\n\t\t\tp.Match(ParserCONSTRAINT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(487)\n\t\t\tp.Name()\n\t\t}\n\n\t}\n\tp.SetState(537)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserPRIMARY_:\n\t\t{\n\t\t\tp.SetState(490)\n\t\t\tp.Match(ParserPRIMARY_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(491)\n\t\t\tp.Match(ParserKEY_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(493)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserASC_ || _la == ParserDESC_ {\n\t\t\t{\n\t\t\t\tp.SetState(492)\n\t\t\t\tp.Asc_desc()\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(496)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserON_ {\n\t\t\t{\n\t\t\t\tp.SetState(495)\n\t\t\t\tp.Conflict_clause()\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(499)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserAUTOINCREMENT_ {\n\t\t\t{\n\t\t\t\tp.SetState(498)\n\t\t\t\tp.Match(ParserAUTOINCREMENT_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tcase ParserNOT_, ParserUNIQUE_:\n\t\tp.SetState(504)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetTokenStream().LA(1) {\n\t\tcase ParserNOT_:\n\t\t\t{\n\t\t\t\tp.SetState(501)\n\t\t\t\tp.Match(ParserNOT_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(502)\n\t\t\t\tp.Match(ParserNULL_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase ParserUNIQUE_:\n\t\t\t{\n\t\t\t\tp.SetState(503)\n\t\t\t\tp.Match(ParserUNIQUE_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tdefault:\n\t\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\t\tgoto errorExit\n\t\t}\n\t\tp.SetState(507)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserON_ {\n\t\t\t{\n\t\t\t\tp.SetState(506)\n\t\t\t\tp.Conflict_clause()\n\t\t\t}\n\n\t\t}\n\n\tcase ParserCHECK_:\n\t\t{\n\t\t\tp.SetState(509)\n\t\t\tp.Match(ParserCHECK_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(510)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(511)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(512)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserDEFAULT_:\n\t\t{\n\t\t\tp.SetState(514)\n\t\t\tp.Match(ParserDEFAULT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(521)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 50, p.GetParserRuleContext()) {\n\t\tcase 1:\n\t\t\t{\n\t\t\t\tp.SetState(515)\n\t\t\t\tp.Signed_number()\n\t\t\t}\n\n\t\tcase 2:\n\t\t\t{\n\t\t\t\tp.SetState(516)\n\t\t\t\tp.Literal_value()\n\t\t\t}\n\n\t\tcase 3:\n\t\t\t{\n\t\t\t\tp.SetState(517)\n\t\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(518)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(519)\n\t\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\tgoto errorExit\n\t\t}\n\n\tcase ParserCOLLATE_:\n\t\t{\n\t\t\tp.SetState(523)\n\t\t\tp.Match(ParserCOLLATE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(524)\n\t\t\tp.Collation_name()\n\t\t}\n\n\tcase ParserREFERENCES_:\n\t\t{\n\t\t\tp.SetState(525)\n\t\t\tp.Foreign_key_clause()\n\t\t}\n\n\tcase ParserAS_, ParserGENERATED_:\n\t\tp.SetState(528)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserGENERATED_ {\n\t\t\t{\n\t\t\t\tp.SetState(526)\n\t\t\t\tp.Match(ParserGENERATED_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(527)\n\t\t\t\tp.Match(ParserALWAYS_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(530)\n\t\t\tp.Match(ParserAS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(531)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(532)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(533)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(535)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserVIRTUAL_ || _la == ParserSTORED_ {\n\t\t\t{\n\t\t\t\tp.SetState(534)\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\tif !(_la == ParserVIRTUAL_ || _la == ParserSTORED_) {\n\t\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t\t} else {\n\t\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\t\tp.Consume()\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISigned_numberContext is an interface to support dynamic dispatch.\ntype ISigned_numberContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tNUMERIC_LITERAL() antlr.TerminalNode\n\tPLUS() antlr.TerminalNode\n\tMINUS() antlr.TerminalNode\n\n\t// IsSigned_numberContext differentiates from other interfaces.\n\tIsSigned_numberContext()\n}\n\ntype Signed_numberContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySigned_numberContext() *Signed_numberContext {\n\tvar p = new(Signed_numberContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_signed_number\n\treturn p\n}\n\nfunc InitEmptySigned_numberContext(p *Signed_numberContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_signed_number\n}\n\nfunc (*Signed_numberContext) IsSigned_numberContext() {}\n\nfunc NewSigned_numberContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Signed_numberContext {\n\tvar p = new(Signed_numberContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_signed_number\n\n\treturn p\n}\n\nfunc (s *Signed_numberContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Signed_numberContext) NUMERIC_LITERAL() antlr.TerminalNode {\n\treturn s.GetToken(ParserNUMERIC_LITERAL, 0)\n}\n\nfunc (s *Signed_numberContext) PLUS() antlr.TerminalNode {\n\treturn s.GetToken(ParserPLUS, 0)\n}\n\nfunc (s *Signed_numberContext) MINUS() antlr.TerminalNode {\n\treturn s.GetToken(ParserMINUS, 0)\n}\n\nfunc (s *Signed_numberContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Signed_numberContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Signed_numberContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSigned_number(s)\n\t}\n}\n\nfunc (s *Signed_numberContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSigned_number(s)\n\t}\n}\n\nfunc (s *Signed_numberContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSigned_number(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Signed_number() (localctx ISigned_numberContext) {\n\tlocalctx = NewSigned_numberContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 34, ParserRULE_signed_number)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(540)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserPLUS || _la == ParserMINUS {\n\t\t{\n\t\t\tp.SetState(539)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserPLUS || _la == ParserMINUS) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(542)\n\t\tp.Match(ParserNUMERIC_LITERAL)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ITable_constraintContext is an interface to support dynamic dispatch.\ntype ITable_constraintContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tOPEN_PAR() antlr.TerminalNode\n\tAllIndexed_column() []IIndexed_columnContext\n\tIndexed_column(i int) IIndexed_columnContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tCHECK_() antlr.TerminalNode\n\tExpr() IExprContext\n\tFOREIGN_() antlr.TerminalNode\n\tKEY_() antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tForeign_key_clause() IForeign_key_clauseContext\n\tCONSTRAINT_() antlr.TerminalNode\n\tName() INameContext\n\tPRIMARY_() antlr.TerminalNode\n\tUNIQUE_() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\tConflict_clause() IConflict_clauseContext\n\n\t// IsTable_constraintContext differentiates from other interfaces.\n\tIsTable_constraintContext()\n}\n\ntype Table_constraintContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyTable_constraintContext() *Table_constraintContext {\n\tvar p = new(Table_constraintContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_constraint\n\treturn p\n}\n\nfunc InitEmptyTable_constraintContext(p *Table_constraintContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_constraint\n}\n\nfunc (*Table_constraintContext) IsTable_constraintContext() {}\n\nfunc NewTable_constraintContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_constraintContext {\n\tvar p = new(Table_constraintContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_table_constraint\n\n\treturn p\n}\n\nfunc (s *Table_constraintContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Table_constraintContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Table_constraintContext) AllIndexed_column() []IIndexed_columnContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IIndexed_columnContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IIndexed_columnContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IIndexed_columnContext); ok {\n\t\t\ttst[i] = t.(IIndexed_columnContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Table_constraintContext) Indexed_column(i int) IIndexed_columnContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IIndexed_columnContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IIndexed_columnContext)\n}\n\nfunc (s *Table_constraintContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Table_constraintContext) CHECK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCHECK_, 0)\n}\n\nfunc (s *Table_constraintContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Table_constraintContext) FOREIGN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFOREIGN_, 0)\n}\n\nfunc (s *Table_constraintContext) KEY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserKEY_, 0)\n}\n\nfunc (s *Table_constraintContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Table_constraintContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Table_constraintContext) Foreign_key_clause() IForeign_key_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IForeign_key_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IForeign_key_clauseContext)\n}\n\nfunc (s *Table_constraintContext) CONSTRAINT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCONSTRAINT_, 0)\n}\n\nfunc (s *Table_constraintContext) Name() INameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(INameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(INameContext)\n}\n\nfunc (s *Table_constraintContext) PRIMARY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPRIMARY_, 0)\n}\n\nfunc (s *Table_constraintContext) UNIQUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNIQUE_, 0)\n}\n\nfunc (s *Table_constraintContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Table_constraintContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Table_constraintContext) Conflict_clause() IConflict_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IConflict_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IConflict_clauseContext)\n}\n\nfunc (s *Table_constraintContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Table_constraintContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Table_constraintContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterTable_constraint(s)\n\t}\n}\n\nfunc (s *Table_constraintContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitTable_constraint(s)\n\t}\n}\n\nfunc (s *Table_constraintContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitTable_constraint(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Table_constraint() (localctx ITable_constraintContext) {\n\tlocalctx = NewTable_constraintContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 36, ParserRULE_table_constraint)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(546)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserCONSTRAINT_ {\n\t\t{\n\t\t\tp.SetState(544)\n\t\t\tp.Match(ParserCONSTRAINT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(545)\n\t\t\tp.Name()\n\t\t}\n\n\t}\n\tp.SetState(585)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserPRIMARY_, ParserUNIQUE_:\n\t\tp.SetState(551)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetTokenStream().LA(1) {\n\t\tcase ParserPRIMARY_:\n\t\t\t{\n\t\t\t\tp.SetState(548)\n\t\t\t\tp.Match(ParserPRIMARY_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(549)\n\t\t\t\tp.Match(ParserKEY_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase ParserUNIQUE_:\n\t\t\t{\n\t\t\t\tp.SetState(550)\n\t\t\t\tp.Match(ParserUNIQUE_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tdefault:\n\t\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(553)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(554)\n\t\t\tp.Indexed_column()\n\t\t}\n\t\tp.SetState(559)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(555)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(556)\n\t\t\t\tp.Indexed_column()\n\t\t\t}\n\n\t\t\tp.SetState(561)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(562)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(564)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserON_ {\n\t\t\t{\n\t\t\t\tp.SetState(563)\n\t\t\t\tp.Conflict_clause()\n\t\t\t}\n\n\t\t}\n\n\tcase ParserCHECK_:\n\t\t{\n\t\t\tp.SetState(566)\n\t\t\tp.Match(ParserCHECK_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(567)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(568)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(569)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserFOREIGN_:\n\t\t{\n\t\t\tp.SetState(571)\n\t\t\tp.Match(ParserFOREIGN_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(572)\n\t\t\tp.Match(ParserKEY_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(573)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(574)\n\t\t\tp.Column_name()\n\t\t}\n\t\tp.SetState(579)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(575)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(576)\n\t\t\t\tp.Column_name()\n\t\t\t}\n\n\t\t\tp.SetState(581)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(582)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(583)\n\t\t\tp.Foreign_key_clause()\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IForeign_key_clauseContext is an interface to support dynamic dispatch.\ntype IForeign_key_clauseContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tREFERENCES_() antlr.TerminalNode\n\tForeign_table() IForeign_tableContext\n\tOPEN_PAR() antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tAllON_() []antlr.TerminalNode\n\tON_(i int) antlr.TerminalNode\n\tAllMATCH_() []antlr.TerminalNode\n\tMATCH_(i int) antlr.TerminalNode\n\tAllName() []INameContext\n\tName(i int) INameContext\n\tDEFERRABLE_() antlr.TerminalNode\n\tAllDELETE_() []antlr.TerminalNode\n\tDELETE_(i int) antlr.TerminalNode\n\tAllUPDATE_() []antlr.TerminalNode\n\tUPDATE_(i int) antlr.TerminalNode\n\tAllSET_() []antlr.TerminalNode\n\tSET_(i int) antlr.TerminalNode\n\tAllCASCADE_() []antlr.TerminalNode\n\tCASCADE_(i int) antlr.TerminalNode\n\tAllRESTRICT_() []antlr.TerminalNode\n\tRESTRICT_(i int) antlr.TerminalNode\n\tAllNO_() []antlr.TerminalNode\n\tNO_(i int) antlr.TerminalNode\n\tAllACTION_() []antlr.TerminalNode\n\tACTION_(i int) antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\tAllNULL_() []antlr.TerminalNode\n\tNULL_(i int) antlr.TerminalNode\n\tAllDEFAULT_() []antlr.TerminalNode\n\tDEFAULT_(i int) antlr.TerminalNode\n\tNOT_() antlr.TerminalNode\n\tINITIALLY_() antlr.TerminalNode\n\tDEFERRED_() antlr.TerminalNode\n\tIMMEDIATE_() antlr.TerminalNode\n\n\t// IsForeign_key_clauseContext differentiates from other interfaces.\n\tIsForeign_key_clauseContext()\n}\n\ntype Foreign_key_clauseContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyForeign_key_clauseContext() *Foreign_key_clauseContext {\n\tvar p = new(Foreign_key_clauseContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_foreign_key_clause\n\treturn p\n}\n\nfunc InitEmptyForeign_key_clauseContext(p *Foreign_key_clauseContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_foreign_key_clause\n}\n\nfunc (*Foreign_key_clauseContext) IsForeign_key_clauseContext() {}\n\nfunc NewForeign_key_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Foreign_key_clauseContext {\n\tvar p = new(Foreign_key_clauseContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_foreign_key_clause\n\n\treturn p\n}\n\nfunc (s *Foreign_key_clauseContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Foreign_key_clauseContext) REFERENCES_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREFERENCES_, 0)\n}\n\nfunc (s *Foreign_key_clauseContext) Foreign_table() IForeign_tableContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IForeign_tableContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IForeign_tableContext)\n}\n\nfunc (s *Foreign_key_clauseContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Foreign_key_clauseContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Foreign_key_clauseContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Foreign_key_clauseContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Foreign_key_clauseContext) AllON_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserON_)\n}\n\nfunc (s *Foreign_key_clauseContext) ON_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserON_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllMATCH_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserMATCH_)\n}\n\nfunc (s *Foreign_key_clauseContext) MATCH_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserMATCH_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllName() []INameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(INameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]INameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(INameContext); ok {\n\t\t\ttst[i] = t.(INameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Foreign_key_clauseContext) Name(i int) INameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(INameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(INameContext)\n}\n\nfunc (s *Foreign_key_clauseContext) DEFERRABLE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDEFERRABLE_, 0)\n}\n\nfunc (s *Foreign_key_clauseContext) AllDELETE_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserDELETE_)\n}\n\nfunc (s *Foreign_key_clauseContext) DELETE_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserDELETE_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllUPDATE_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserUPDATE_)\n}\n\nfunc (s *Foreign_key_clauseContext) UPDATE_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserUPDATE_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllSET_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserSET_)\n}\n\nfunc (s *Foreign_key_clauseContext) SET_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserSET_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllCASCADE_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCASCADE_)\n}\n\nfunc (s *Foreign_key_clauseContext) CASCADE_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCASCADE_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllRESTRICT_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserRESTRICT_)\n}\n\nfunc (s *Foreign_key_clauseContext) RESTRICT_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserRESTRICT_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllNO_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserNO_)\n}\n\nfunc (s *Foreign_key_clauseContext) NO_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserNO_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllACTION_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserACTION_)\n}\n\nfunc (s *Foreign_key_clauseContext) ACTION_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserACTION_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Foreign_key_clauseContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllNULL_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserNULL_)\n}\n\nfunc (s *Foreign_key_clauseContext) NULL_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserNULL_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) AllDEFAULT_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserDEFAULT_)\n}\n\nfunc (s *Foreign_key_clauseContext) DEFAULT_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserDEFAULT_, i)\n}\n\nfunc (s *Foreign_key_clauseContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *Foreign_key_clauseContext) INITIALLY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINITIALLY_, 0)\n}\n\nfunc (s *Foreign_key_clauseContext) DEFERRED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDEFERRED_, 0)\n}\n\nfunc (s *Foreign_key_clauseContext) IMMEDIATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIMMEDIATE_, 0)\n}\n\nfunc (s *Foreign_key_clauseContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Foreign_key_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Foreign_key_clauseContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterForeign_key_clause(s)\n\t}\n}\n\nfunc (s *Foreign_key_clauseContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitForeign_key_clause(s)\n\t}\n}\n\nfunc (s *Foreign_key_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitForeign_key_clause(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Foreign_key_clause() (localctx IForeign_key_clauseContext) {\n\tlocalctx = NewForeign_key_clauseContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 38, ParserRULE_foreign_key_clause)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(587)\n\t\tp.Match(ParserREFERENCES_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(588)\n\t\tp.Foreign_table()\n\t}\n\tp.SetState(600)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserOPEN_PAR {\n\t\t{\n\t\t\tp.SetState(589)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(590)\n\t\t\tp.Column_name()\n\t\t}\n\t\tp.SetState(595)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(591)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(592)\n\t\t\t\tp.Column_name()\n\t\t\t}\n\n\t\t\tp.SetState(597)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(598)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\tp.SetState(616)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserMATCH_ || _la == ParserON_ {\n\t\tp.SetState(614)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetTokenStream().LA(1) {\n\t\tcase ParserON_:\n\t\t\t{\n\t\t\t\tp.SetState(602)\n\t\t\t\tp.Match(ParserON_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(603)\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\tif !(_la == ParserDELETE_ || _la == ParserUPDATE_) {\n\t\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t\t} else {\n\t\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\t\tp.Consume()\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.SetState(610)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\n\t\t\tswitch p.GetTokenStream().LA(1) {\n\t\t\tcase ParserSET_:\n\t\t\t\t{\n\t\t\t\t\tp.SetState(604)\n\t\t\t\t\tp.Match(ParserSET_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(605)\n\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\t\tif !(_la == ParserDEFAULT_ || _la == ParserNULL_) {\n\t\t\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\t\t\tp.Consume()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tcase ParserCASCADE_:\n\t\t\t\t{\n\t\t\t\t\tp.SetState(606)\n\t\t\t\t\tp.Match(ParserCASCADE_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tcase ParserRESTRICT_:\n\t\t\t\t{\n\t\t\t\t\tp.SetState(607)\n\t\t\t\t\tp.Match(ParserRESTRICT_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tcase ParserNO_:\n\t\t\t\t{\n\t\t\t\t\tp.SetState(608)\n\t\t\t\t\tp.Match(ParserNO_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(609)\n\t\t\t\t\tp.Match(ParserACTION_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\t\t\tgoto errorExit\n\t\t\t}\n\n\t\tcase ParserMATCH_:\n\t\t\t{\n\t\t\t\tp.SetState(612)\n\t\t\t\tp.Match(ParserMATCH_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(613)\n\t\t\t\tp.Name()\n\t\t\t}\n\n\t\tdefault:\n\t\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tp.SetState(618)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\tp.SetState(627)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 68, p.GetParserRuleContext()) == 1 {\n\t\tp.SetState(620)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserNOT_ {\n\t\t\t{\n\t\t\t\tp.SetState(619)\n\t\t\t\tp.Match(ParserNOT_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(622)\n\t\t\tp.Match(ParserDEFERRABLE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(625)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserINITIALLY_ {\n\t\t\t{\n\t\t\t\tp.SetState(623)\n\t\t\t\tp.Match(ParserINITIALLY_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(624)\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\tif !(_la == ParserDEFERRED_ || _la == ParserIMMEDIATE_) {\n\t\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t\t} else {\n\t\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\t\tp.Consume()\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IConflict_clauseContext is an interface to support dynamic dispatch.\ntype IConflict_clauseContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tON_() antlr.TerminalNode\n\tCONFLICT_() antlr.TerminalNode\n\tROLLBACK_() antlr.TerminalNode\n\tABORT_() antlr.TerminalNode\n\tFAIL_() antlr.TerminalNode\n\tIGNORE_() antlr.TerminalNode\n\tREPLACE_() antlr.TerminalNode\n\n\t// IsConflict_clauseContext differentiates from other interfaces.\n\tIsConflict_clauseContext()\n}\n\ntype Conflict_clauseContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyConflict_clauseContext() *Conflict_clauseContext {\n\tvar p = new(Conflict_clauseContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_conflict_clause\n\treturn p\n}\n\nfunc InitEmptyConflict_clauseContext(p *Conflict_clauseContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_conflict_clause\n}\n\nfunc (*Conflict_clauseContext) IsConflict_clauseContext() {}\n\nfunc NewConflict_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Conflict_clauseContext {\n\tvar p = new(Conflict_clauseContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_conflict_clause\n\n\treturn p\n}\n\nfunc (s *Conflict_clauseContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Conflict_clauseContext) ON_() antlr.TerminalNode {\n\treturn s.GetToken(ParserON_, 0)\n}\n\nfunc (s *Conflict_clauseContext) CONFLICT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCONFLICT_, 0)\n}\n\nfunc (s *Conflict_clauseContext) ROLLBACK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROLLBACK_, 0)\n}\n\nfunc (s *Conflict_clauseContext) ABORT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserABORT_, 0)\n}\n\nfunc (s *Conflict_clauseContext) FAIL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFAIL_, 0)\n}\n\nfunc (s *Conflict_clauseContext) IGNORE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIGNORE_, 0)\n}\n\nfunc (s *Conflict_clauseContext) REPLACE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREPLACE_, 0)\n}\n\nfunc (s *Conflict_clauseContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Conflict_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Conflict_clauseContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterConflict_clause(s)\n\t}\n}\n\nfunc (s *Conflict_clauseContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitConflict_clause(s)\n\t}\n}\n\nfunc (s *Conflict_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitConflict_clause(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Conflict_clause() (localctx IConflict_clauseContext) {\n\tlocalctx = NewConflict_clauseContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 40, ParserRULE_conflict_clause)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(629)\n\t\tp.Match(ParserON_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(630)\n\t\tp.Match(ParserCONFLICT_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(631)\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif !(_la == ParserABORT_ || ((int64((_la-72)) & ^0x3f) == 0 && ((int64(1)<<(_la-72))&19140298416325121) != 0)) {\n\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t} else {\n\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\tp.Consume()\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICreate_trigger_stmtContext is an interface to support dynamic dispatch.\ntype ICreate_trigger_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tCREATE_() antlr.TerminalNode\n\tTRIGGER_() antlr.TerminalNode\n\tTrigger_name() ITrigger_nameContext\n\tON_() antlr.TerminalNode\n\tTable_name() ITable_nameContext\n\tBEGIN_() antlr.TerminalNode\n\tEND_() antlr.TerminalNode\n\tDELETE_() antlr.TerminalNode\n\tINSERT_() antlr.TerminalNode\n\tUPDATE_() antlr.TerminalNode\n\tIF_() antlr.TerminalNode\n\tNOT_() antlr.TerminalNode\n\tEXISTS_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\tBEFORE_() antlr.TerminalNode\n\tAFTER_() antlr.TerminalNode\n\tINSTEAD_() antlr.TerminalNode\n\tAllOF_() []antlr.TerminalNode\n\tOF_(i int) antlr.TerminalNode\n\tFOR_() antlr.TerminalNode\n\tEACH_() antlr.TerminalNode\n\tROW_() antlr.TerminalNode\n\tWHEN_() antlr.TerminalNode\n\tExpr() IExprContext\n\tAllSCOL() []antlr.TerminalNode\n\tSCOL(i int) antlr.TerminalNode\n\tTEMP_() antlr.TerminalNode\n\tTEMPORARY_() antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tAllUpdate_stmt() []IUpdate_stmtContext\n\tUpdate_stmt(i int) IUpdate_stmtContext\n\tAllInsert_stmt() []IInsert_stmtContext\n\tInsert_stmt(i int) IInsert_stmtContext\n\tAllDelete_stmt() []IDelete_stmtContext\n\tDelete_stmt(i int) IDelete_stmtContext\n\tAllSelect_stmt() []ISelect_stmtContext\n\tSelect_stmt(i int) ISelect_stmtContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsCreate_trigger_stmtContext differentiates from other interfaces.\n\tIsCreate_trigger_stmtContext()\n}\n\ntype Create_trigger_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCreate_trigger_stmtContext() *Create_trigger_stmtContext {\n\tvar p = new(Create_trigger_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_create_trigger_stmt\n\treturn p\n}\n\nfunc InitEmptyCreate_trigger_stmtContext(p *Create_trigger_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_create_trigger_stmt\n}\n\nfunc (*Create_trigger_stmtContext) IsCreate_trigger_stmtContext() {}\n\nfunc NewCreate_trigger_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Create_trigger_stmtContext {\n\tvar p = new(Create_trigger_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_create_trigger_stmt\n\n\treturn p\n}\n\nfunc (s *Create_trigger_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Create_trigger_stmtContext) CREATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCREATE_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) TRIGGER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTRIGGER_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) Trigger_name() ITrigger_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITrigger_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITrigger_nameContext)\n}\n\nfunc (s *Create_trigger_stmtContext) ON_() antlr.TerminalNode {\n\treturn s.GetToken(ParserON_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Create_trigger_stmtContext) BEGIN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBEGIN_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) END_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEND_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) DELETE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDELETE_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) INSERT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINSERT_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) UPDATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUPDATE_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) IF_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIF_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) EXISTS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXISTS_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Create_trigger_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) BEFORE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBEFORE_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) AFTER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAFTER_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) INSTEAD_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINSTEAD_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) AllOF_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserOF_)\n}\n\nfunc (s *Create_trigger_stmtContext) OF_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserOF_, i)\n}\n\nfunc (s *Create_trigger_stmtContext) FOR_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFOR_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) EACH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEACH_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) ROW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROW_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) WHEN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWHEN_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Create_trigger_stmtContext) AllSCOL() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserSCOL)\n}\n\nfunc (s *Create_trigger_stmtContext) SCOL(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserSCOL, i)\n}\n\nfunc (s *Create_trigger_stmtContext) TEMP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTEMP_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) TEMPORARY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTEMPORARY_, 0)\n}\n\nfunc (s *Create_trigger_stmtContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Create_trigger_stmtContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Create_trigger_stmtContext) AllUpdate_stmt() []IUpdate_stmtContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IUpdate_stmtContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IUpdate_stmtContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IUpdate_stmtContext); ok {\n\t\t\ttst[i] = t.(IUpdate_stmtContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Create_trigger_stmtContext) Update_stmt(i int) IUpdate_stmtContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IUpdate_stmtContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IUpdate_stmtContext)\n}\n\nfunc (s *Create_trigger_stmtContext) AllInsert_stmt() []IInsert_stmtContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IInsert_stmtContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IInsert_stmtContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IInsert_stmtContext); ok {\n\t\t\ttst[i] = t.(IInsert_stmtContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Create_trigger_stmtContext) Insert_stmt(i int) IInsert_stmtContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IInsert_stmtContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IInsert_stmtContext)\n}\n\nfunc (s *Create_trigger_stmtContext) AllDelete_stmt() []IDelete_stmtContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IDelete_stmtContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IDelete_stmtContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IDelete_stmtContext); ok {\n\t\t\ttst[i] = t.(IDelete_stmtContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Create_trigger_stmtContext) Delete_stmt(i int) IDelete_stmtContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IDelete_stmtContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IDelete_stmtContext)\n}\n\nfunc (s *Create_trigger_stmtContext) AllSelect_stmt() []ISelect_stmtContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ISelect_stmtContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\ttst[i] = t.(ISelect_stmtContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Create_trigger_stmtContext) Select_stmt(i int) ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *Create_trigger_stmtContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Create_trigger_stmtContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Create_trigger_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Create_trigger_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Create_trigger_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCreate_trigger_stmt(s)\n\t}\n}\n\nfunc (s *Create_trigger_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCreate_trigger_stmt(s)\n\t}\n}\n\nfunc (s *Create_trigger_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCreate_trigger_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Create_trigger_stmt() (localctx ICreate_trigger_stmtContext) {\n\tlocalctx = NewCreate_trigger_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 42, ParserRULE_create_trigger_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(633)\n\t\tp.Match(ParserCREATE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(635)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserTEMP_ || _la == ParserTEMPORARY_ {\n\t\t{\n\t\t\tp.SetState(634)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserTEMP_ || _la == ParserTEMPORARY_) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(637)\n\t\tp.Match(ParserTRIGGER_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(641)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 70, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(638)\n\t\t\tp.Match(ParserIF_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(639)\n\t\t\tp.Match(ParserNOT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(640)\n\t\t\tp.Match(ParserEXISTS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\tp.SetState(646)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 71, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(643)\n\t\t\tp.Schema_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(644)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(648)\n\t\tp.Trigger_name()\n\t}\n\tp.SetState(653)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserBEFORE_:\n\t\t{\n\t\t\tp.SetState(649)\n\t\t\tp.Match(ParserBEFORE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserAFTER_:\n\t\t{\n\t\t\tp.SetState(650)\n\t\t\tp.Match(ParserAFTER_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserINSTEAD_:\n\t\t{\n\t\t\tp.SetState(651)\n\t\t\tp.Match(ParserINSTEAD_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(652)\n\t\t\tp.Match(ParserOF_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserDELETE_, ParserINSERT_, ParserUPDATE_:\n\n\tdefault:\n\t}\n\tp.SetState(669)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserDELETE_:\n\t\t{\n\t\t\tp.SetState(655)\n\t\t\tp.Match(ParserDELETE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserINSERT_:\n\t\t{\n\t\t\tp.SetState(656)\n\t\t\tp.Match(ParserINSERT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserUPDATE_:\n\t\t{\n\t\t\tp.SetState(657)\n\t\t\tp.Match(ParserUPDATE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(667)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserOF_ {\n\t\t\t{\n\t\t\t\tp.SetState(658)\n\t\t\t\tp.Match(ParserOF_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(659)\n\t\t\t\tp.Column_name()\n\t\t\t}\n\t\t\tp.SetState(664)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(660)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(661)\n\t\t\t\t\tp.Column_name()\n\t\t\t\t}\n\n\t\t\t\tp.SetState(666)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(671)\n\t\tp.Match(ParserON_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(672)\n\t\tp.Table_name()\n\t}\n\tp.SetState(676)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserFOR_ {\n\t\t{\n\t\t\tp.SetState(673)\n\t\t\tp.Match(ParserFOR_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(674)\n\t\t\tp.Match(ParserEACH_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(675)\n\t\t\tp.Match(ParserROW_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\tp.SetState(680)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWHEN_ {\n\t\t{\n\t\t\tp.SetState(678)\n\t\t\tp.Match(ParserWHEN_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(679)\n\t\t\tp.expr(0)\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(682)\n\t\tp.Match(ParserBEGIN_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(691)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor ok := true; ok; ok = _la == ParserDELETE_ || ((int64((_la-88)) & ^0x3f) == 0 && ((int64(1)<<(_la-88))&2386912217732743169) != 0) {\n\t\tp.SetState(687)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 78, p.GetParserRuleContext()) {\n\t\tcase 1:\n\t\t\t{\n\t\t\t\tp.SetState(683)\n\t\t\t\tp.Update_stmt()\n\t\t\t}\n\n\t\tcase 2:\n\t\t\t{\n\t\t\t\tp.SetState(684)\n\t\t\t\tp.Insert_stmt()\n\t\t\t}\n\n\t\tcase 3:\n\t\t\t{\n\t\t\t\tp.SetState(685)\n\t\t\t\tp.Delete_stmt()\n\t\t\t}\n\n\t\tcase 4:\n\t\t\t{\n\t\t\t\tp.SetState(686)\n\t\t\t\tp.Select_stmt()\n\t\t\t}\n\n\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(689)\n\t\t\tp.Match(ParserSCOL)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t\tp.SetState(693)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\t{\n\t\tp.SetState(695)\n\t\tp.Match(ParserEND_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICreate_view_stmtContext is an interface to support dynamic dispatch.\ntype ICreate_view_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tCREATE_() antlr.TerminalNode\n\tVIEW_() antlr.TerminalNode\n\tView_name() IView_nameContext\n\tAS_() antlr.TerminalNode\n\tSelect_stmt() ISelect_stmtContext\n\tIF_() antlr.TerminalNode\n\tNOT_() antlr.TerminalNode\n\tEXISTS_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\tOPEN_PAR() antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tTEMP_() antlr.TerminalNode\n\tTEMPORARY_() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsCreate_view_stmtContext differentiates from other interfaces.\n\tIsCreate_view_stmtContext()\n}\n\ntype Create_view_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCreate_view_stmtContext() *Create_view_stmtContext {\n\tvar p = new(Create_view_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_create_view_stmt\n\treturn p\n}\n\nfunc InitEmptyCreate_view_stmtContext(p *Create_view_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_create_view_stmt\n}\n\nfunc (*Create_view_stmtContext) IsCreate_view_stmtContext() {}\n\nfunc NewCreate_view_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Create_view_stmtContext {\n\tvar p = new(Create_view_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_create_view_stmt\n\n\treturn p\n}\n\nfunc (s *Create_view_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Create_view_stmtContext) CREATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCREATE_, 0)\n}\n\nfunc (s *Create_view_stmtContext) VIEW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVIEW_, 0)\n}\n\nfunc (s *Create_view_stmtContext) View_name() IView_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IView_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IView_nameContext)\n}\n\nfunc (s *Create_view_stmtContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *Create_view_stmtContext) Select_stmt() ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *Create_view_stmtContext) IF_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIF_, 0)\n}\n\nfunc (s *Create_view_stmtContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *Create_view_stmtContext) EXISTS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXISTS_, 0)\n}\n\nfunc (s *Create_view_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Create_view_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Create_view_stmtContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Create_view_stmtContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Create_view_stmtContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Create_view_stmtContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Create_view_stmtContext) TEMP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTEMP_, 0)\n}\n\nfunc (s *Create_view_stmtContext) TEMPORARY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTEMPORARY_, 0)\n}\n\nfunc (s *Create_view_stmtContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Create_view_stmtContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Create_view_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Create_view_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Create_view_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCreate_view_stmt(s)\n\t}\n}\n\nfunc (s *Create_view_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCreate_view_stmt(s)\n\t}\n}\n\nfunc (s *Create_view_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCreate_view_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Create_view_stmt() (localctx ICreate_view_stmtContext) {\n\tlocalctx = NewCreate_view_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 44, ParserRULE_create_view_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(697)\n\t\tp.Match(ParserCREATE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(699)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserTEMP_ || _la == ParserTEMPORARY_ {\n\t\t{\n\t\t\tp.SetState(698)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserTEMP_ || _la == ParserTEMPORARY_) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(701)\n\t\tp.Match(ParserVIEW_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(705)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 81, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(702)\n\t\t\tp.Match(ParserIF_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(703)\n\t\t\tp.Match(ParserNOT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(704)\n\t\t\tp.Match(ParserEXISTS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\tp.SetState(710)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 82, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(707)\n\t\t\tp.Schema_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(708)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(712)\n\t\tp.View_name()\n\t}\n\tp.SetState(724)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserOPEN_PAR {\n\t\t{\n\t\t\tp.SetState(713)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(714)\n\t\t\tp.Column_name()\n\t\t}\n\t\tp.SetState(719)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(715)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(716)\n\t\t\t\tp.Column_name()\n\t\t\t}\n\n\t\t\tp.SetState(721)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(722)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(726)\n\t\tp.Match(ParserAS_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(727)\n\t\tp.Select_stmt()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICreate_virtual_table_stmtContext is an interface to support dynamic dispatch.\ntype ICreate_virtual_table_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tCREATE_() antlr.TerminalNode\n\tVIRTUAL_() antlr.TerminalNode\n\tTABLE_() antlr.TerminalNode\n\tTable_name() ITable_nameContext\n\tUSING_() antlr.TerminalNode\n\tModule_name() IModule_nameContext\n\tIF_() antlr.TerminalNode\n\tNOT_() antlr.TerminalNode\n\tEXISTS_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\tOPEN_PAR() antlr.TerminalNode\n\tAllModule_argument() []IModule_argumentContext\n\tModule_argument(i int) IModule_argumentContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsCreate_virtual_table_stmtContext differentiates from other interfaces.\n\tIsCreate_virtual_table_stmtContext()\n}\n\ntype Create_virtual_table_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCreate_virtual_table_stmtContext() *Create_virtual_table_stmtContext {\n\tvar p = new(Create_virtual_table_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_create_virtual_table_stmt\n\treturn p\n}\n\nfunc InitEmptyCreate_virtual_table_stmtContext(p *Create_virtual_table_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_create_virtual_table_stmt\n}\n\nfunc (*Create_virtual_table_stmtContext) IsCreate_virtual_table_stmtContext() {}\n\nfunc NewCreate_virtual_table_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Create_virtual_table_stmtContext {\n\tvar p = new(Create_virtual_table_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_create_virtual_table_stmt\n\n\treturn p\n}\n\nfunc (s *Create_virtual_table_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Create_virtual_table_stmtContext) CREATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCREATE_, 0)\n}\n\nfunc (s *Create_virtual_table_stmtContext) VIRTUAL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVIRTUAL_, 0)\n}\n\nfunc (s *Create_virtual_table_stmtContext) TABLE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTABLE_, 0)\n}\n\nfunc (s *Create_virtual_table_stmtContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Create_virtual_table_stmtContext) USING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUSING_, 0)\n}\n\nfunc (s *Create_virtual_table_stmtContext) Module_name() IModule_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IModule_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IModule_nameContext)\n}\n\nfunc (s *Create_virtual_table_stmtContext) IF_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIF_, 0)\n}\n\nfunc (s *Create_virtual_table_stmtContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *Create_virtual_table_stmtContext) EXISTS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXISTS_, 0)\n}\n\nfunc (s *Create_virtual_table_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Create_virtual_table_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Create_virtual_table_stmtContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Create_virtual_table_stmtContext) AllModule_argument() []IModule_argumentContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IModule_argumentContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IModule_argumentContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IModule_argumentContext); ok {\n\t\t\ttst[i] = t.(IModule_argumentContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Create_virtual_table_stmtContext) Module_argument(i int) IModule_argumentContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IModule_argumentContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IModule_argumentContext)\n}\n\nfunc (s *Create_virtual_table_stmtContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Create_virtual_table_stmtContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Create_virtual_table_stmtContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Create_virtual_table_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Create_virtual_table_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Create_virtual_table_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCreate_virtual_table_stmt(s)\n\t}\n}\n\nfunc (s *Create_virtual_table_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCreate_virtual_table_stmt(s)\n\t}\n}\n\nfunc (s *Create_virtual_table_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCreate_virtual_table_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Create_virtual_table_stmt() (localctx ICreate_virtual_table_stmtContext) {\n\tlocalctx = NewCreate_virtual_table_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 46, ParserRULE_create_virtual_table_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(729)\n\t\tp.Match(ParserCREATE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(730)\n\t\tp.Match(ParserVIRTUAL_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(731)\n\t\tp.Match(ParserTABLE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(735)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 85, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(732)\n\t\t\tp.Match(ParserIF_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(733)\n\t\t\tp.Match(ParserNOT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(734)\n\t\t\tp.Match(ParserEXISTS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\tp.SetState(740)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 86, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(737)\n\t\t\tp.Schema_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(738)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(742)\n\t\tp.Table_name()\n\t}\n\t{\n\t\tp.SetState(743)\n\t\tp.Match(ParserUSING_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(744)\n\t\tp.Module_name()\n\t}\n\tp.SetState(756)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserOPEN_PAR {\n\t\t{\n\t\t\tp.SetState(745)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(746)\n\t\t\tp.Module_argument()\n\t\t}\n\t\tp.SetState(751)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(747)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(748)\n\t\t\t\tp.Module_argument()\n\t\t\t}\n\n\t\t\tp.SetState(753)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(754)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IWith_clauseContext is an interface to support dynamic dispatch.\ntype IWith_clauseContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tWITH_() antlr.TerminalNode\n\tAllCte_table_name() []ICte_table_nameContext\n\tCte_table_name(i int) ICte_table_nameContext\n\tAllAS_() []antlr.TerminalNode\n\tAS_(i int) antlr.TerminalNode\n\tAllOPEN_PAR() []antlr.TerminalNode\n\tOPEN_PAR(i int) antlr.TerminalNode\n\tAllSelect_stmt() []ISelect_stmtContext\n\tSelect_stmt(i int) ISelect_stmtContext\n\tAllCLOSE_PAR() []antlr.TerminalNode\n\tCLOSE_PAR(i int) antlr.TerminalNode\n\tRECURSIVE_() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsWith_clauseContext differentiates from other interfaces.\n\tIsWith_clauseContext()\n}\n\ntype With_clauseContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyWith_clauseContext() *With_clauseContext {\n\tvar p = new(With_clauseContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_with_clause\n\treturn p\n}\n\nfunc InitEmptyWith_clauseContext(p *With_clauseContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_with_clause\n}\n\nfunc (*With_clauseContext) IsWith_clauseContext() {}\n\nfunc NewWith_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *With_clauseContext {\n\tvar p = new(With_clauseContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_with_clause\n\n\treturn p\n}\n\nfunc (s *With_clauseContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *With_clauseContext) WITH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWITH_, 0)\n}\n\nfunc (s *With_clauseContext) AllCte_table_name() []ICte_table_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ICte_table_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ICte_table_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ICte_table_nameContext); ok {\n\t\t\ttst[i] = t.(ICte_table_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *With_clauseContext) Cte_table_name(i int) ICte_table_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICte_table_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICte_table_nameContext)\n}\n\nfunc (s *With_clauseContext) AllAS_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserAS_)\n}\n\nfunc (s *With_clauseContext) AS_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, i)\n}\n\nfunc (s *With_clauseContext) AllOPEN_PAR() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserOPEN_PAR)\n}\n\nfunc (s *With_clauseContext) OPEN_PAR(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, i)\n}\n\nfunc (s *With_clauseContext) AllSelect_stmt() []ISelect_stmtContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ISelect_stmtContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\ttst[i] = t.(ISelect_stmtContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *With_clauseContext) Select_stmt(i int) ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *With_clauseContext) AllCLOSE_PAR() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCLOSE_PAR)\n}\n\nfunc (s *With_clauseContext) CLOSE_PAR(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, i)\n}\n\nfunc (s *With_clauseContext) RECURSIVE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRECURSIVE_, 0)\n}\n\nfunc (s *With_clauseContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *With_clauseContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *With_clauseContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *With_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *With_clauseContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterWith_clause(s)\n\t}\n}\n\nfunc (s *With_clauseContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitWith_clause(s)\n\t}\n}\n\nfunc (s *With_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitWith_clause(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) With_clause() (localctx IWith_clauseContext) {\n\tlocalctx = NewWith_clauseContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 48, ParserRULE_with_clause)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(758)\n\t\tp.Match(ParserWITH_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(760)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 89, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(759)\n\t\t\tp.Match(ParserRECURSIVE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(762)\n\t\tp.Cte_table_name()\n\t}\n\t{\n\t\tp.SetState(763)\n\t\tp.Match(ParserAS_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(764)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(765)\n\t\tp.Select_stmt()\n\t}\n\t{\n\t\tp.SetState(766)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(776)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA {\n\t\t{\n\t\t\tp.SetState(767)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(768)\n\t\t\tp.Cte_table_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(769)\n\t\t\tp.Match(ParserAS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(770)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(771)\n\t\t\tp.Select_stmt()\n\t\t}\n\t\t{\n\t\t\tp.SetState(772)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t\tp.SetState(778)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICte_table_nameContext is an interface to support dynamic dispatch.\ntype ICte_table_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tTable_name() ITable_nameContext\n\tOPEN_PAR() antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsCte_table_nameContext differentiates from other interfaces.\n\tIsCte_table_nameContext()\n}\n\ntype Cte_table_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCte_table_nameContext() *Cte_table_nameContext {\n\tvar p = new(Cte_table_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_cte_table_name\n\treturn p\n}\n\nfunc InitEmptyCte_table_nameContext(p *Cte_table_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_cte_table_name\n}\n\nfunc (*Cte_table_nameContext) IsCte_table_nameContext() {}\n\nfunc NewCte_table_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Cte_table_nameContext {\n\tvar p = new(Cte_table_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_cte_table_name\n\n\treturn p\n}\n\nfunc (s *Cte_table_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Cte_table_nameContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Cte_table_nameContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Cte_table_nameContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Cte_table_nameContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Cte_table_nameContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Cte_table_nameContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Cte_table_nameContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Cte_table_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Cte_table_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Cte_table_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCte_table_name(s)\n\t}\n}\n\nfunc (s *Cte_table_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCte_table_name(s)\n\t}\n}\n\nfunc (s *Cte_table_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCte_table_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Cte_table_name() (localctx ICte_table_nameContext) {\n\tlocalctx = NewCte_table_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 50, ParserRULE_cte_table_name)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(779)\n\t\tp.Table_name()\n\t}\n\tp.SetState(791)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserOPEN_PAR {\n\t\t{\n\t\t\tp.SetState(780)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(781)\n\t\t\tp.Column_name()\n\t\t}\n\t\tp.SetState(786)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(782)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(783)\n\t\t\t\tp.Column_name()\n\t\t\t}\n\n\t\t\tp.SetState(788)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(789)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IRecursive_cteContext is an interface to support dynamic dispatch.\ntype IRecursive_cteContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tCte_table_name() ICte_table_nameContext\n\tAS_() antlr.TerminalNode\n\tOPEN_PAR() antlr.TerminalNode\n\tInitial_select() IInitial_selectContext\n\tUNION_() antlr.TerminalNode\n\tRecursive_select() IRecursive_selectContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tALL_() antlr.TerminalNode\n\n\t// IsRecursive_cteContext differentiates from other interfaces.\n\tIsRecursive_cteContext()\n}\n\ntype Recursive_cteContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyRecursive_cteContext() *Recursive_cteContext {\n\tvar p = new(Recursive_cteContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_recursive_cte\n\treturn p\n}\n\nfunc InitEmptyRecursive_cteContext(p *Recursive_cteContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_recursive_cte\n}\n\nfunc (*Recursive_cteContext) IsRecursive_cteContext() {}\n\nfunc NewRecursive_cteContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Recursive_cteContext {\n\tvar p = new(Recursive_cteContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_recursive_cte\n\n\treturn p\n}\n\nfunc (s *Recursive_cteContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Recursive_cteContext) Cte_table_name() ICte_table_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICte_table_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICte_table_nameContext)\n}\n\nfunc (s *Recursive_cteContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *Recursive_cteContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Recursive_cteContext) Initial_select() IInitial_selectContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IInitial_selectContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IInitial_selectContext)\n}\n\nfunc (s *Recursive_cteContext) UNION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNION_, 0)\n}\n\nfunc (s *Recursive_cteContext) Recursive_select() IRecursive_selectContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IRecursive_selectContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IRecursive_selectContext)\n}\n\nfunc (s *Recursive_cteContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Recursive_cteContext) ALL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserALL_, 0)\n}\n\nfunc (s *Recursive_cteContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Recursive_cteContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Recursive_cteContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterRecursive_cte(s)\n\t}\n}\n\nfunc (s *Recursive_cteContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitRecursive_cte(s)\n\t}\n}\n\nfunc (s *Recursive_cteContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitRecursive_cte(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Recursive_cte() (localctx IRecursive_cteContext) {\n\tlocalctx = NewRecursive_cteContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 52, ParserRULE_recursive_cte)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(793)\n\t\tp.Cte_table_name()\n\t}\n\t{\n\t\tp.SetState(794)\n\t\tp.Match(ParserAS_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(795)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(796)\n\t\tp.Initial_select()\n\t}\n\t{\n\t\tp.SetState(797)\n\t\tp.Match(ParserUNION_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(799)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserALL_ {\n\t\t{\n\t\t\tp.SetState(798)\n\t\t\tp.Match(ParserALL_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(801)\n\t\tp.Recursive_select()\n\t}\n\t{\n\t\tp.SetState(802)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICommon_table_expressionContext is an interface to support dynamic dispatch.\ntype ICommon_table_expressionContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tTable_name() ITable_nameContext\n\tAS_() antlr.TerminalNode\n\tAllOPEN_PAR() []antlr.TerminalNode\n\tOPEN_PAR(i int) antlr.TerminalNode\n\tSelect_stmt() ISelect_stmtContext\n\tAllCLOSE_PAR() []antlr.TerminalNode\n\tCLOSE_PAR(i int) antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsCommon_table_expressionContext differentiates from other interfaces.\n\tIsCommon_table_expressionContext()\n}\n\ntype Common_table_expressionContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCommon_table_expressionContext() *Common_table_expressionContext {\n\tvar p = new(Common_table_expressionContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_common_table_expression\n\treturn p\n}\n\nfunc InitEmptyCommon_table_expressionContext(p *Common_table_expressionContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_common_table_expression\n}\n\nfunc (*Common_table_expressionContext) IsCommon_table_expressionContext() {}\n\nfunc NewCommon_table_expressionContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Common_table_expressionContext {\n\tvar p = new(Common_table_expressionContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_common_table_expression\n\n\treturn p\n}\n\nfunc (s *Common_table_expressionContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Common_table_expressionContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Common_table_expressionContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *Common_table_expressionContext) AllOPEN_PAR() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserOPEN_PAR)\n}\n\nfunc (s *Common_table_expressionContext) OPEN_PAR(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, i)\n}\n\nfunc (s *Common_table_expressionContext) Select_stmt() ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *Common_table_expressionContext) AllCLOSE_PAR() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCLOSE_PAR)\n}\n\nfunc (s *Common_table_expressionContext) CLOSE_PAR(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, i)\n}\n\nfunc (s *Common_table_expressionContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Common_table_expressionContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Common_table_expressionContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Common_table_expressionContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Common_table_expressionContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Common_table_expressionContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Common_table_expressionContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCommon_table_expression(s)\n\t}\n}\n\nfunc (s *Common_table_expressionContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCommon_table_expression(s)\n\t}\n}\n\nfunc (s *Common_table_expressionContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCommon_table_expression(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Common_table_expression() (localctx ICommon_table_expressionContext) {\n\tlocalctx = NewCommon_table_expressionContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 54, ParserRULE_common_table_expression)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(804)\n\t\tp.Table_name()\n\t}\n\tp.SetState(816)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserOPEN_PAR {\n\t\t{\n\t\t\tp.SetState(805)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(806)\n\t\t\tp.Column_name()\n\t\t}\n\t\tp.SetState(811)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(807)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(808)\n\t\t\t\tp.Column_name()\n\t\t\t}\n\n\t\t\tp.SetState(813)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(814)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(818)\n\t\tp.Match(ParserAS_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(819)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(820)\n\t\tp.Select_stmt()\n\t}\n\t{\n\t\tp.SetState(821)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IDelete_stmtContext is an interface to support dynamic dispatch.\ntype IDelete_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tDELETE_() antlr.TerminalNode\n\tFROM_() antlr.TerminalNode\n\tQualified_table_name() IQualified_table_nameContext\n\tWith_clause() IWith_clauseContext\n\tWHERE_() antlr.TerminalNode\n\tExpr() IExprContext\n\tReturning_clause() IReturning_clauseContext\n\n\t// IsDelete_stmtContext differentiates from other interfaces.\n\tIsDelete_stmtContext()\n}\n\ntype Delete_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyDelete_stmtContext() *Delete_stmtContext {\n\tvar p = new(Delete_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_delete_stmt\n\treturn p\n}\n\nfunc InitEmptyDelete_stmtContext(p *Delete_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_delete_stmt\n}\n\nfunc (*Delete_stmtContext) IsDelete_stmtContext() {}\n\nfunc NewDelete_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Delete_stmtContext {\n\tvar p = new(Delete_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_delete_stmt\n\n\treturn p\n}\n\nfunc (s *Delete_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Delete_stmtContext) DELETE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDELETE_, 0)\n}\n\nfunc (s *Delete_stmtContext) FROM_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFROM_, 0)\n}\n\nfunc (s *Delete_stmtContext) Qualified_table_name() IQualified_table_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IQualified_table_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IQualified_table_nameContext)\n}\n\nfunc (s *Delete_stmtContext) With_clause() IWith_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWith_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWith_clauseContext)\n}\n\nfunc (s *Delete_stmtContext) WHERE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWHERE_, 0)\n}\n\nfunc (s *Delete_stmtContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Delete_stmtContext) Returning_clause() IReturning_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IReturning_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IReturning_clauseContext)\n}\n\nfunc (s *Delete_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Delete_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Delete_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterDelete_stmt(s)\n\t}\n}\n\nfunc (s *Delete_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitDelete_stmt(s)\n\t}\n}\n\nfunc (s *Delete_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitDelete_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Delete_stmt() (localctx IDelete_stmtContext) {\n\tlocalctx = NewDelete_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 56, ParserRULE_delete_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(824)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWITH_ {\n\t\t{\n\t\t\tp.SetState(823)\n\t\t\tp.With_clause()\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(826)\n\t\tp.Match(ParserDELETE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(827)\n\t\tp.Match(ParserFROM_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(828)\n\t\tp.Qualified_table_name()\n\t}\n\tp.SetState(831)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWHERE_ {\n\t\t{\n\t\t\tp.SetState(829)\n\t\t\tp.Match(ParserWHERE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(830)\n\t\t\tp.expr(0)\n\t\t}\n\n\t}\n\tp.SetState(834)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserRETURNING_ {\n\t\t{\n\t\t\tp.SetState(833)\n\t\t\tp.Returning_clause()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IDelete_stmt_limitedContext is an interface to support dynamic dispatch.\ntype IDelete_stmt_limitedContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tDELETE_() antlr.TerminalNode\n\tFROM_() antlr.TerminalNode\n\tQualified_table_name() IQualified_table_nameContext\n\tWith_clause() IWith_clauseContext\n\tWHERE_() antlr.TerminalNode\n\tExpr() IExprContext\n\tReturning_clause() IReturning_clauseContext\n\tLimit_stmt() ILimit_stmtContext\n\tOrder_by_stmt() IOrder_by_stmtContext\n\n\t// IsDelete_stmt_limitedContext differentiates from other interfaces.\n\tIsDelete_stmt_limitedContext()\n}\n\ntype Delete_stmt_limitedContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyDelete_stmt_limitedContext() *Delete_stmt_limitedContext {\n\tvar p = new(Delete_stmt_limitedContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_delete_stmt_limited\n\treturn p\n}\n\nfunc InitEmptyDelete_stmt_limitedContext(p *Delete_stmt_limitedContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_delete_stmt_limited\n}\n\nfunc (*Delete_stmt_limitedContext) IsDelete_stmt_limitedContext() {}\n\nfunc NewDelete_stmt_limitedContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Delete_stmt_limitedContext {\n\tvar p = new(Delete_stmt_limitedContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_delete_stmt_limited\n\n\treturn p\n}\n\nfunc (s *Delete_stmt_limitedContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Delete_stmt_limitedContext) DELETE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDELETE_, 0)\n}\n\nfunc (s *Delete_stmt_limitedContext) FROM_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFROM_, 0)\n}\n\nfunc (s *Delete_stmt_limitedContext) Qualified_table_name() IQualified_table_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IQualified_table_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IQualified_table_nameContext)\n}\n\nfunc (s *Delete_stmt_limitedContext) With_clause() IWith_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWith_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWith_clauseContext)\n}\n\nfunc (s *Delete_stmt_limitedContext) WHERE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWHERE_, 0)\n}\n\nfunc (s *Delete_stmt_limitedContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Delete_stmt_limitedContext) Returning_clause() IReturning_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IReturning_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IReturning_clauseContext)\n}\n\nfunc (s *Delete_stmt_limitedContext) Limit_stmt() ILimit_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ILimit_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ILimit_stmtContext)\n}\n\nfunc (s *Delete_stmt_limitedContext) Order_by_stmt() IOrder_by_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOrder_by_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOrder_by_stmtContext)\n}\n\nfunc (s *Delete_stmt_limitedContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Delete_stmt_limitedContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Delete_stmt_limitedContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterDelete_stmt_limited(s)\n\t}\n}\n\nfunc (s *Delete_stmt_limitedContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitDelete_stmt_limited(s)\n\t}\n}\n\nfunc (s *Delete_stmt_limitedContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitDelete_stmt_limited(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Delete_stmt_limited() (localctx IDelete_stmt_limitedContext) {\n\tlocalctx = NewDelete_stmt_limitedContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 58, ParserRULE_delete_stmt_limited)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(837)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWITH_ {\n\t\t{\n\t\t\tp.SetState(836)\n\t\t\tp.With_clause()\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(839)\n\t\tp.Match(ParserDELETE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(840)\n\t\tp.Match(ParserFROM_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(841)\n\t\tp.Qualified_table_name()\n\t}\n\tp.SetState(844)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWHERE_ {\n\t\t{\n\t\t\tp.SetState(842)\n\t\t\tp.Match(ParserWHERE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(843)\n\t\t\tp.expr(0)\n\t\t}\n\n\t}\n\tp.SetState(847)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserRETURNING_ {\n\t\t{\n\t\t\tp.SetState(846)\n\t\t\tp.Returning_clause()\n\t\t}\n\n\t}\n\tp.SetState(853)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserLIMIT_ || _la == ParserORDER_ {\n\t\tp.SetState(850)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserORDER_ {\n\t\t\t{\n\t\t\t\tp.SetState(849)\n\t\t\t\tp.Order_by_stmt()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(852)\n\t\t\tp.Limit_stmt()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IDetach_stmtContext is an interface to support dynamic dispatch.\ntype IDetach_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tDETACH_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tDATABASE_() antlr.TerminalNode\n\n\t// IsDetach_stmtContext differentiates from other interfaces.\n\tIsDetach_stmtContext()\n}\n\ntype Detach_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyDetach_stmtContext() *Detach_stmtContext {\n\tvar p = new(Detach_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_detach_stmt\n\treturn p\n}\n\nfunc InitEmptyDetach_stmtContext(p *Detach_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_detach_stmt\n}\n\nfunc (*Detach_stmtContext) IsDetach_stmtContext() {}\n\nfunc NewDetach_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Detach_stmtContext {\n\tvar p = new(Detach_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_detach_stmt\n\n\treturn p\n}\n\nfunc (s *Detach_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Detach_stmtContext) DETACH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDETACH_, 0)\n}\n\nfunc (s *Detach_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Detach_stmtContext) DATABASE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDATABASE_, 0)\n}\n\nfunc (s *Detach_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Detach_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Detach_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterDetach_stmt(s)\n\t}\n}\n\nfunc (s *Detach_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitDetach_stmt(s)\n\t}\n}\n\nfunc (s *Detach_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitDetach_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Detach_stmt() (localctx IDetach_stmtContext) {\n\tlocalctx = NewDetach_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 60, ParserRULE_detach_stmt)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(855)\n\t\tp.Match(ParserDETACH_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(857)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 104, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(856)\n\t\t\tp.Match(ParserDATABASE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(859)\n\t\tp.Schema_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IDrop_stmtContext is an interface to support dynamic dispatch.\ntype IDrop_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// GetObject returns the object token.\n\tGetObject() antlr.Token\n\n\t// SetObject sets the object token.\n\tSetObject(antlr.Token)\n\n\t// Getter signatures\n\tDROP_() antlr.TerminalNode\n\tAny_name() IAny_nameContext\n\tINDEX_() antlr.TerminalNode\n\tTABLE_() antlr.TerminalNode\n\tTRIGGER_() antlr.TerminalNode\n\tVIEW_() antlr.TerminalNode\n\tIF_() antlr.TerminalNode\n\tEXISTS_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\n\t// IsDrop_stmtContext differentiates from other interfaces.\n\tIsDrop_stmtContext()\n}\n\ntype Drop_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n\tobject antlr.Token\n}\n\nfunc NewEmptyDrop_stmtContext() *Drop_stmtContext {\n\tvar p = new(Drop_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_drop_stmt\n\treturn p\n}\n\nfunc InitEmptyDrop_stmtContext(p *Drop_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_drop_stmt\n}\n\nfunc (*Drop_stmtContext) IsDrop_stmtContext() {}\n\nfunc NewDrop_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Drop_stmtContext {\n\tvar p = new(Drop_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_drop_stmt\n\n\treturn p\n}\n\nfunc (s *Drop_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Drop_stmtContext) GetObject() antlr.Token { return s.object }\n\nfunc (s *Drop_stmtContext) SetObject(v antlr.Token) { s.object = v }\n\nfunc (s *Drop_stmtContext) DROP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDROP_, 0)\n}\n\nfunc (s *Drop_stmtContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Drop_stmtContext) INDEX_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINDEX_, 0)\n}\n\nfunc (s *Drop_stmtContext) TABLE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTABLE_, 0)\n}\n\nfunc (s *Drop_stmtContext) TRIGGER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTRIGGER_, 0)\n}\n\nfunc (s *Drop_stmtContext) VIEW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVIEW_, 0)\n}\n\nfunc (s *Drop_stmtContext) IF_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIF_, 0)\n}\n\nfunc (s *Drop_stmtContext) EXISTS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXISTS_, 0)\n}\n\nfunc (s *Drop_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Drop_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Drop_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Drop_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Drop_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterDrop_stmt(s)\n\t}\n}\n\nfunc (s *Drop_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitDrop_stmt(s)\n\t}\n}\n\nfunc (s *Drop_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitDrop_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Drop_stmt() (localctx IDrop_stmtContext) {\n\tlocalctx = NewDrop_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 62, ParserRULE_drop_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(861)\n\t\tp.Match(ParserDROP_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(862)\n\n\t\tvar _lt = p.GetTokenStream().LT(1)\n\n\t\tlocalctx.(*Drop_stmtContext).object = _lt\n\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif !((int64((_la-84)) & ^0x3f) == 0 && ((int64(1)<<(_la-84))&2324138882699886593) != 0) {\n\t\t\tvar _ri = p.GetErrorHandler().RecoverInline(p)\n\n\t\t\tlocalctx.(*Drop_stmtContext).object = _ri\n\t\t} else {\n\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\tp.Consume()\n\t\t}\n\t}\n\tp.SetState(865)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 105, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(863)\n\t\t\tp.Match(ParserIF_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(864)\n\t\t\tp.Match(ParserEXISTS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\tp.SetState(870)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 106, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(867)\n\t\t\tp.Schema_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(868)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(872)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IExprContext is an interface to support dynamic dispatch.\ntype IExprContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tLiteral_value() ILiteral_valueContext\n\tBIND_PARAMETER() antlr.TerminalNode\n\tColumn_name() IColumn_nameContext\n\tTable_name() ITable_nameContext\n\tAllDOT() []antlr.TerminalNode\n\tDOT(i int) antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tUnary_operator() IUnary_operatorContext\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tFunction_name() IFunction_nameContext\n\tOPEN_PAR() antlr.TerminalNode\n\tCLOSE_PAR() antlr.TerminalNode\n\tSTAR() antlr.TerminalNode\n\tFilter_clause() IFilter_clauseContext\n\tOver_clause() IOver_clauseContext\n\tDISTINCT_() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\tCAST_() antlr.TerminalNode\n\tAS_() antlr.TerminalNode\n\tType_name() IType_nameContext\n\tSelect_stmt() ISelect_stmtContext\n\tEXISTS_() antlr.TerminalNode\n\tNOT_() antlr.TerminalNode\n\tCASE_() antlr.TerminalNode\n\tEND_() antlr.TerminalNode\n\tAllWHEN_() []antlr.TerminalNode\n\tWHEN_(i int) antlr.TerminalNode\n\tAllTHEN_() []antlr.TerminalNode\n\tTHEN_(i int) antlr.TerminalNode\n\tELSE_() antlr.TerminalNode\n\tRaise_function() IRaise_functionContext\n\tPIPE2() antlr.TerminalNode\n\tDIV() antlr.TerminalNode\n\tMOD() antlr.TerminalNode\n\tPLUS() antlr.TerminalNode\n\tMINUS() antlr.TerminalNode\n\tLT2() antlr.TerminalNode\n\tGT2() antlr.TerminalNode\n\tAMP() antlr.TerminalNode\n\tPIPE() antlr.TerminalNode\n\tLT() antlr.TerminalNode\n\tLT_EQ() antlr.TerminalNode\n\tGT() antlr.TerminalNode\n\tGT_EQ() antlr.TerminalNode\n\tASSIGN() antlr.TerminalNode\n\tEQ() antlr.TerminalNode\n\tNOT_EQ1() antlr.TerminalNode\n\tNOT_EQ2() antlr.TerminalNode\n\tIS_() antlr.TerminalNode\n\tIN_() antlr.TerminalNode\n\tLIKE_() antlr.TerminalNode\n\tGLOB_() antlr.TerminalNode\n\tMATCH_() antlr.TerminalNode\n\tREGEXP_() antlr.TerminalNode\n\tAND_() antlr.TerminalNode\n\tOR_() antlr.TerminalNode\n\tBETWEEN_() antlr.TerminalNode\n\tCOLLATE_() antlr.TerminalNode\n\tCollation_name() ICollation_nameContext\n\tESCAPE_() antlr.TerminalNode\n\tISNULL_() antlr.TerminalNode\n\tNOTNULL_() antlr.TerminalNode\n\tNULL_() antlr.TerminalNode\n\tTable_function_name() ITable_function_nameContext\n\n\t// IsExprContext differentiates from other interfaces.\n\tIsExprContext()\n}\n\ntype ExprContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyExprContext() *ExprContext {\n\tvar p = new(ExprContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_expr\n\treturn p\n}\n\nfunc InitEmptyExprContext(p *ExprContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_expr\n}\n\nfunc (*ExprContext) IsExprContext() {}\n\nfunc NewExprContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ExprContext {\n\tvar p = new(ExprContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_expr\n\n\treturn p\n}\n\nfunc (s *ExprContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *ExprContext) Literal_value() ILiteral_valueContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ILiteral_valueContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ILiteral_valueContext)\n}\n\nfunc (s *ExprContext) BIND_PARAMETER() antlr.TerminalNode {\n\treturn s.GetToken(ParserBIND_PARAMETER, 0)\n}\n\nfunc (s *ExprContext) Column_name() IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *ExprContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *ExprContext) AllDOT() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserDOT)\n}\n\nfunc (s *ExprContext) DOT(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, i)\n}\n\nfunc (s *ExprContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *ExprContext) Unary_operator() IUnary_operatorContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IUnary_operatorContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IUnary_operatorContext)\n}\n\nfunc (s *ExprContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *ExprContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *ExprContext) Function_name() IFunction_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFunction_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFunction_nameContext)\n}\n\nfunc (s *ExprContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *ExprContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *ExprContext) STAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTAR, 0)\n}\n\nfunc (s *ExprContext) Filter_clause() IFilter_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFilter_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFilter_clauseContext)\n}\n\nfunc (s *ExprContext) Over_clause() IOver_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOver_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOver_clauseContext)\n}\n\nfunc (s *ExprContext) DISTINCT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDISTINCT_, 0)\n}\n\nfunc (s *ExprContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *ExprContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *ExprContext) CAST_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCAST_, 0)\n}\n\nfunc (s *ExprContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *ExprContext) Type_name() IType_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IType_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IType_nameContext)\n}\n\nfunc (s *ExprContext) Select_stmt() ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *ExprContext) EXISTS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXISTS_, 0)\n}\n\nfunc (s *ExprContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *ExprContext) CASE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCASE_, 0)\n}\n\nfunc (s *ExprContext) END_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEND_, 0)\n}\n\nfunc (s *ExprContext) AllWHEN_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserWHEN_)\n}\n\nfunc (s *ExprContext) WHEN_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserWHEN_, i)\n}\n\nfunc (s *ExprContext) AllTHEN_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserTHEN_)\n}\n\nfunc (s *ExprContext) THEN_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserTHEN_, i)\n}\n\nfunc (s *ExprContext) ELSE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserELSE_, 0)\n}\n\nfunc (s *ExprContext) Raise_function() IRaise_functionContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IRaise_functionContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IRaise_functionContext)\n}\n\nfunc (s *ExprContext) PIPE2() antlr.TerminalNode {\n\treturn s.GetToken(ParserPIPE2, 0)\n}\n\nfunc (s *ExprContext) DIV() antlr.TerminalNode {\n\treturn s.GetToken(ParserDIV, 0)\n}\n\nfunc (s *ExprContext) MOD() antlr.TerminalNode {\n\treturn s.GetToken(ParserMOD, 0)\n}\n\nfunc (s *ExprContext) PLUS() antlr.TerminalNode {\n\treturn s.GetToken(ParserPLUS, 0)\n}\n\nfunc (s *ExprContext) MINUS() antlr.TerminalNode {\n\treturn s.GetToken(ParserMINUS, 0)\n}\n\nfunc (s *ExprContext) LT2() antlr.TerminalNode {\n\treturn s.GetToken(ParserLT2, 0)\n}\n\nfunc (s *ExprContext) GT2() antlr.TerminalNode {\n\treturn s.GetToken(ParserGT2, 0)\n}\n\nfunc (s *ExprContext) AMP() antlr.TerminalNode {\n\treturn s.GetToken(ParserAMP, 0)\n}\n\nfunc (s *ExprContext) PIPE() antlr.TerminalNode {\n\treturn s.GetToken(ParserPIPE, 0)\n}\n\nfunc (s *ExprContext) LT() antlr.TerminalNode {\n\treturn s.GetToken(ParserLT, 0)\n}\n\nfunc (s *ExprContext) LT_EQ() antlr.TerminalNode {\n\treturn s.GetToken(ParserLT_EQ, 0)\n}\n\nfunc (s *ExprContext) GT() antlr.TerminalNode {\n\treturn s.GetToken(ParserGT, 0)\n}\n\nfunc (s *ExprContext) GT_EQ() antlr.TerminalNode {\n\treturn s.GetToken(ParserGT_EQ, 0)\n}\n\nfunc (s *ExprContext) ASSIGN() antlr.TerminalNode {\n\treturn s.GetToken(ParserASSIGN, 0)\n}\n\nfunc (s *ExprContext) EQ() antlr.TerminalNode {\n\treturn s.GetToken(ParserEQ, 0)\n}\n\nfunc (s *ExprContext) NOT_EQ1() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_EQ1, 0)\n}\n\nfunc (s *ExprContext) NOT_EQ2() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_EQ2, 0)\n}\n\nfunc (s *ExprContext) IS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIS_, 0)\n}\n\nfunc (s *ExprContext) IN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIN_, 0)\n}\n\nfunc (s *ExprContext) LIKE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLIKE_, 0)\n}\n\nfunc (s *ExprContext) GLOB_() antlr.TerminalNode {\n\treturn s.GetToken(ParserGLOB_, 0)\n}\n\nfunc (s *ExprContext) MATCH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserMATCH_, 0)\n}\n\nfunc (s *ExprContext) REGEXP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREGEXP_, 0)\n}\n\nfunc (s *ExprContext) AND_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAND_, 0)\n}\n\nfunc (s *ExprContext) OR_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOR_, 0)\n}\n\nfunc (s *ExprContext) BETWEEN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBETWEEN_, 0)\n}\n\nfunc (s *ExprContext) COLLATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOLLATE_, 0)\n}\n\nfunc (s *ExprContext) Collation_name() ICollation_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICollation_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICollation_nameContext)\n}\n\nfunc (s *ExprContext) ESCAPE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserESCAPE_, 0)\n}\n\nfunc (s *ExprContext) ISNULL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserISNULL_, 0)\n}\n\nfunc (s *ExprContext) NOTNULL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOTNULL_, 0)\n}\n\nfunc (s *ExprContext) NULL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNULL_, 0)\n}\n\nfunc (s *ExprContext) Table_function_name() ITable_function_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_function_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_function_nameContext)\n}\n\nfunc (s *ExprContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *ExprContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *ExprContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterExpr(s)\n\t}\n}\n\nfunc (s *ExprContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitExpr(s)\n\t}\n}\n\nfunc (s *ExprContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitExpr(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Expr() (localctx IExprContext) {\n\treturn p.expr(0)\n}\n\nfunc (p *Parser) expr(_p int) (localctx IExprContext) {\n\tvar _parentctx antlr.ParserRuleContext = p.GetParserRuleContext()\n\n\t_parentState := p.GetState()\n\tlocalctx = NewExprContext(p, p.GetParserRuleContext(), _parentState)\n\tvar _prevctx IExprContext = localctx\n\tvar _ antlr.ParserRuleContext = _prevctx // TODO: To prevent unused variable warning.\n\t_startState := 64\n\tp.EnterRecursionRule(localctx, 64, ParserRULE_expr, _p)\n\tvar _la int\n\n\tvar _alt int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(962)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 120, p.GetParserRuleContext()) {\n\tcase 1:\n\t\t{\n\t\t\tp.SetState(875)\n\t\t\tp.Literal_value()\n\t\t}\n\n\tcase 2:\n\t\t{\n\t\t\tp.SetState(876)\n\t\t\tp.Match(ParserBIND_PARAMETER)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 3:\n\t\tp.SetState(885)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 108, p.GetParserRuleContext()) == 1 {\n\t\t\tp.SetState(880)\n\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 107, p.GetParserRuleContext()) == 1 {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(877)\n\t\t\t\t\tp.Schema_name()\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(878)\n\t\t\t\t\tp.Match(ParserDOT)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else if p.HasError() { // JIM\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(882)\n\t\t\t\tp.Table_name()\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(883)\n\t\t\t\tp.Match(ParserDOT)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(887)\n\t\t\tp.Column_name()\n\t\t}\n\n\tcase 4:\n\t\t{\n\t\t\tp.SetState(888)\n\t\t\tp.Unary_operator()\n\t\t}\n\t\t{\n\t\t\tp.SetState(889)\n\t\t\tp.expr(21)\n\t\t}\n\n\tcase 5:\n\t\t{\n\t\t\tp.SetState(891)\n\t\t\tp.Function_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(892)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(905)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\tswitch p.GetTokenStream().LA(1) {\n\t\tcase 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:\n\t\t\tp.SetState(894)\n\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 109, p.GetParserRuleContext()) == 1 {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(893)\n\t\t\t\t\tp.Match(ParserDISTINCT_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else if p.HasError() { // JIM\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(896)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\t\t\tp.SetState(901)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(897)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(898)\n\t\t\t\t\tp.expr(0)\n\t\t\t\t}\n\n\t\t\t\tp.SetState(903)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\n\t\tcase ParserSTAR:\n\t\t\t{\n\t\t\t\tp.SetState(904)\n\t\t\t\tp.Match(ParserSTAR)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase ParserCLOSE_PAR:\n\n\t\tdefault:\n\t\t}\n\t\t{\n\t\t\tp.SetState(907)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(909)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 112, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(908)\n\t\t\t\tp.Filter_clause()\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\tp.SetState(912)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 113, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(911)\n\t\t\t\tp.Over_clause()\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\n\tcase 6:\n\t\t{\n\t\t\tp.SetState(914)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(915)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(920)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(916)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(917)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t\tp.SetState(922)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(923)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 7:\n\t\t{\n\t\t\tp.SetState(925)\n\t\t\tp.Match(ParserCAST_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(926)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(927)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(928)\n\t\t\tp.Match(ParserAS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(929)\n\t\t\tp.Type_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(930)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 8:\n\t\tp.SetState(936)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserEXISTS_ || _la == ParserNOT_ {\n\t\t\tp.SetState(933)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif _la == ParserNOT_ {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(932)\n\t\t\t\t\tp.Match(ParserNOT_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(935)\n\t\t\t\tp.Match(ParserEXISTS_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(938)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(939)\n\t\t\tp.Select_stmt()\n\t\t}\n\t\t{\n\t\t\tp.SetState(940)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 9:\n\t\t{\n\t\t\tp.SetState(942)\n\t\t\tp.Match(ParserCASE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(944)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 117, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(943)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\tp.SetState(951)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor ok := true; ok; ok = _la == ParserWHEN_ {\n\t\t\t{\n\t\t\t\tp.SetState(946)\n\t\t\t\tp.Match(ParserWHEN_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(947)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(948)\n\t\t\t\tp.Match(ParserTHEN_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(949)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t\tp.SetState(953)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\tp.SetState(957)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserELSE_ {\n\t\t\t{\n\t\t\t\tp.SetState(955)\n\t\t\t\tp.Match(ParserELSE_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(956)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(959)\n\t\t\tp.Match(ParserEND_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 10:\n\t\t{\n\t\t\tp.SetState(961)\n\t\t\tp.Raise_function()\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\tp.GetParserRuleContext().SetStop(p.GetTokenStream().LT(-1))\n\tp.SetState(1083)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 136, p.GetParserRuleContext())\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\tfor _alt != 2 && _alt != antlr.ATNInvalidAltNumber {\n\t\tif _alt == 1 {\n\t\t\tif p.GetParseListeners() != nil {\n\t\t\t\tp.TriggerExitRuleEvent()\n\t\t\t}\n\t\t\t_prevctx = localctx\n\t\t\tp.SetState(1081)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\n\t\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 135, p.GetParserRuleContext()) {\n\t\t\tcase 1:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(964)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 20)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 20)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(965)\n\t\t\t\t\tp.Match(ParserPIPE2)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(966)\n\t\t\t\t\tp.expr(21)\n\t\t\t\t}\n\n\t\t\tcase 2:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(967)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 19)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 19)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(968)\n\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\t\tif !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&12416) != 0) {\n\t\t\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\t\t\tp.Consume()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(969)\n\t\t\t\t\tp.expr(20)\n\t\t\t\t}\n\n\t\t\tcase 3:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(970)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 18)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 18)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(971)\n\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\t\tif !(_la == ParserPLUS || _la == ParserMINUS) {\n\t\t\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\t\t\tp.Consume()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(972)\n\t\t\t\t\tp.expr(19)\n\t\t\t\t}\n\n\t\t\tcase 4:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(973)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 17)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 17)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(974)\n\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\t\tif !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&245760) != 0) {\n\t\t\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\t\t\tp.Consume()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(975)\n\t\t\t\t\tp.expr(18)\n\t\t\t\t}\n\n\t\t\tcase 5:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(976)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 16)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 16)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(977)\n\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\t\tif !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&3932160) != 0) {\n\t\t\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\t\t\tp.Consume()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(978)\n\t\t\t\t\tp.expr(17)\n\t\t\t\t}\n\n\t\t\tcase 6:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(979)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 15)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 15)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\tp.SetState(992)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\n\t\t\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 121, p.GetParserRuleContext()) {\n\t\t\t\tcase 1:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(980)\n\t\t\t\t\t\tp.Match(ParserASSIGN)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 2:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(981)\n\t\t\t\t\t\tp.Match(ParserEQ)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 3:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(982)\n\t\t\t\t\t\tp.Match(ParserNOT_EQ1)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 4:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(983)\n\t\t\t\t\t\tp.Match(ParserNOT_EQ2)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 5:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(984)\n\t\t\t\t\t\tp.Match(ParserIS_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 6:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(985)\n\t\t\t\t\t\tp.Match(ParserIS_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(986)\n\t\t\t\t\t\tp.Match(ParserNOT_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 7:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(987)\n\t\t\t\t\t\tp.Match(ParserIN_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 8:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(988)\n\t\t\t\t\t\tp.Match(ParserLIKE_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 9:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(989)\n\t\t\t\t\t\tp.Match(ParserGLOB_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 10:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(990)\n\t\t\t\t\t\tp.Match(ParserMATCH_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 11:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(991)\n\t\t\t\t\t\tp.Match(ParserREGEXP_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(994)\n\t\t\t\t\tp.expr(16)\n\t\t\t\t}\n\n\t\t\tcase 7:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(995)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 14)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 14)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(996)\n\t\t\t\t\tp.Match(ParserAND_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(997)\n\t\t\t\t\tp.expr(15)\n\t\t\t\t}\n\n\t\t\tcase 8:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(998)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 13)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 13)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(999)\n\t\t\t\t\tp.Match(ParserOR_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1000)\n\t\t\t\t\tp.expr(14)\n\t\t\t\t}\n\n\t\t\tcase 9:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(1001)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 6)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 6)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1002)\n\t\t\t\t\tp.Match(ParserIS_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tp.SetState(1004)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 122, p.GetParserRuleContext()) == 1 {\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1003)\n\t\t\t\t\t\tp.Match(ParserNOT_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t} else if p.HasError() { // JIM\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1006)\n\t\t\t\t\tp.expr(7)\n\t\t\t\t}\n\n\t\t\tcase 10:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(1007)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 5)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 5)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\tp.SetState(1009)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\tif _la == ParserNOT_ {\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1008)\n\t\t\t\t\t\tp.Match(ParserNOT_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1011)\n\t\t\t\t\tp.Match(ParserBETWEEN_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1012)\n\t\t\t\t\tp.expr(0)\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1013)\n\t\t\t\t\tp.Match(ParserAND_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1014)\n\t\t\t\t\tp.expr(6)\n\t\t\t\t}\n\n\t\t\tcase 11:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(1016)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 9)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 9)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1017)\n\t\t\t\t\tp.Match(ParserCOLLATE_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1018)\n\t\t\t\t\tp.Collation_name()\n\t\t\t\t}\n\n\t\t\tcase 12:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(1019)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 8)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 8)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\tp.SetState(1021)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\tif _la == ParserNOT_ {\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1020)\n\t\t\t\t\t\tp.Match(ParserNOT_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1023)\n\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\t\tif !((int64((_la-77)) & ^0x3f) == 0 && ((int64(1)<<(_la-77))&2199028498433) != 0) {\n\t\t\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\t\t\tp.Consume()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1024)\n\t\t\t\t\tp.expr(0)\n\t\t\t\t}\n\t\t\t\tp.SetState(1027)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 125, p.GetParserRuleContext()) == 1 {\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1025)\n\t\t\t\t\t\tp.Match(ParserESCAPE_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1026)\n\t\t\t\t\t\tp.expr(0)\n\t\t\t\t\t}\n\n\t\t\t\t} else if p.HasError() { // JIM\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\n\t\t\tcase 13:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(1029)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 7)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 7)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\tp.SetState(1034)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\n\t\t\t\tswitch p.GetTokenStream().LA(1) {\n\t\t\t\tcase ParserISNULL_:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1030)\n\t\t\t\t\t\tp.Match(ParserISNULL_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase ParserNOTNULL_:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1031)\n\t\t\t\t\t\tp.Match(ParserNOTNULL_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase ParserNOT_:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1032)\n\t\t\t\t\t\tp.Match(ParserNOT_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1033)\n\t\t\t\t\t\tp.Match(ParserNULL_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\n\t\t\tcase 14:\n\t\t\t\tlocalctx = NewExprContext(p, _parentctx, _parentState)\n\t\t\t\tp.PushNewRecursionContext(localctx, _startState, ParserRULE_expr)\n\t\t\t\tp.SetState(1036)\n\n\t\t\t\tif !(p.Precpred(p.GetParserRuleContext(), 4)) {\n\t\t\t\t\tp.SetError(antlr.NewFailedPredicateException(p, \"p.Precpred(p.GetParserRuleContext(), 4)\", \"\"))\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\tp.SetState(1038)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\tif _la == ParserNOT_ {\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1037)\n\t\t\t\t\t\tp.Match(ParserNOT_)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1040)\n\t\t\t\t\tp.Match(ParserIN_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tp.SetState(1079)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\n\t\t\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 134, p.GetParserRuleContext()) {\n\t\t\t\tcase 1:\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1041)\n\t\t\t\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tp.SetState(1051)\n\t\t\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 129, p.GetParserRuleContext()) == 1 {\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tp.SetState(1042)\n\t\t\t\t\t\t\tp.Select_stmt()\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if p.HasError() { // JIM\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t} else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 129, p.GetParserRuleContext()) == 2 {\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tp.SetState(1043)\n\t\t\t\t\t\t\tp.expr(0)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tp.SetState(1048)\n\t\t\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tp.SetState(1044)\n\t\t\t\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tp.SetState(1045)\n\t\t\t\t\t\t\t\tp.expr(0)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tp.SetState(1050)\n\t\t\t\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if p.HasError() { // JIM\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1053)\n\t\t\t\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 2:\n\t\t\t\t\tp.SetState(1057)\n\t\t\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 130, p.GetParserRuleContext()) == 1 {\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tp.SetState(1054)\n\t\t\t\t\t\t\tp.Schema_name()\n\t\t\t\t\t\t}\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tp.SetState(1055)\n\t\t\t\t\t\t\tp.Match(ParserDOT)\n\t\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if p.HasError() { // JIM\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1059)\n\t\t\t\t\t\tp.Table_name()\n\t\t\t\t\t}\n\n\t\t\t\tcase 3:\n\t\t\t\t\tp.SetState(1063)\n\t\t\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 131, p.GetParserRuleContext()) == 1 {\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tp.SetState(1060)\n\t\t\t\t\t\t\tp.Schema_name()\n\t\t\t\t\t\t}\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tp.SetState(1061)\n\t\t\t\t\t\t\tp.Match(ParserDOT)\n\t\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else if p.HasError() { // JIM\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1065)\n\t\t\t\t\t\tp.Table_function_name()\n\t\t\t\t\t}\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1066)\n\t\t\t\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tp.SetState(1075)\n\t\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\t\tif ((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) {\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tp.SetState(1067)\n\t\t\t\t\t\t\tp.expr(0)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tp.SetState(1072)\n\t\t\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tp.SetState(1068)\n\t\t\t\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tp.SetState(1069)\n\t\t\t\t\t\t\t\tp.expr(0)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tp.SetState(1074)\n\t\t\t\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1077)\n\t\t\t\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\n\t\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\t\tgoto errorExit\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(1085)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 136, p.GetParserRuleContext())\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.UnrollRecursionContexts(_parentctx)\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IRaise_functionContext is an interface to support dynamic dispatch.\ntype IRaise_functionContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tRAISE_() antlr.TerminalNode\n\tOPEN_PAR() antlr.TerminalNode\n\tCLOSE_PAR() antlr.TerminalNode\n\tIGNORE_() antlr.TerminalNode\n\tCOMMA() antlr.TerminalNode\n\tError_message() IError_messageContext\n\tROLLBACK_() antlr.TerminalNode\n\tABORT_() antlr.TerminalNode\n\tFAIL_() antlr.TerminalNode\n\n\t// IsRaise_functionContext differentiates from other interfaces.\n\tIsRaise_functionContext()\n}\n\ntype Raise_functionContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyRaise_functionContext() *Raise_functionContext {\n\tvar p = new(Raise_functionContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_raise_function\n\treturn p\n}\n\nfunc InitEmptyRaise_functionContext(p *Raise_functionContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_raise_function\n}\n\nfunc (*Raise_functionContext) IsRaise_functionContext() {}\n\nfunc NewRaise_functionContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Raise_functionContext {\n\tvar p = new(Raise_functionContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_raise_function\n\n\treturn p\n}\n\nfunc (s *Raise_functionContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Raise_functionContext) RAISE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRAISE_, 0)\n}\n\nfunc (s *Raise_functionContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Raise_functionContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Raise_functionContext) IGNORE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIGNORE_, 0)\n}\n\nfunc (s *Raise_functionContext) COMMA() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, 0)\n}\n\nfunc (s *Raise_functionContext) Error_message() IError_messageContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IError_messageContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IError_messageContext)\n}\n\nfunc (s *Raise_functionContext) ROLLBACK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROLLBACK_, 0)\n}\n\nfunc (s *Raise_functionContext) ABORT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserABORT_, 0)\n}\n\nfunc (s *Raise_functionContext) FAIL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFAIL_, 0)\n}\n\nfunc (s *Raise_functionContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Raise_functionContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Raise_functionContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterRaise_function(s)\n\t}\n}\n\nfunc (s *Raise_functionContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitRaise_function(s)\n\t}\n}\n\nfunc (s *Raise_functionContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitRaise_function(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Raise_function() (localctx IRaise_functionContext) {\n\tlocalctx = NewRaise_functionContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 66, ParserRULE_raise_function)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1086)\n\t\tp.Match(ParserRAISE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1087)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1092)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserIGNORE_:\n\t\t{\n\t\t\tp.SetState(1088)\n\t\t\tp.Match(ParserIGNORE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserABORT_, ParserFAIL_, ParserROLLBACK_:\n\t\t{\n\t\t\tp.SetState(1089)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserABORT_ || _la == ParserFAIL_ || _la == ParserROLLBACK_) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1090)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1091)\n\t\t\tp.Error_message()\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1094)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ILiteral_valueContext is an interface to support dynamic dispatch.\ntype ILiteral_valueContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tNUMERIC_LITERAL() antlr.TerminalNode\n\tSTRING_LITERAL() antlr.TerminalNode\n\tBLOB_LITERAL() antlr.TerminalNode\n\tNULL_() antlr.TerminalNode\n\tTRUE_() antlr.TerminalNode\n\tFALSE_() antlr.TerminalNode\n\tCURRENT_TIME_() antlr.TerminalNode\n\tCURRENT_DATE_() antlr.TerminalNode\n\tCURRENT_TIMESTAMP_() antlr.TerminalNode\n\n\t// IsLiteral_valueContext differentiates from other interfaces.\n\tIsLiteral_valueContext()\n}\n\ntype Literal_valueContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyLiteral_valueContext() *Literal_valueContext {\n\tvar p = new(Literal_valueContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_literal_value\n\treturn p\n}\n\nfunc InitEmptyLiteral_valueContext(p *Literal_valueContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_literal_value\n}\n\nfunc (*Literal_valueContext) IsLiteral_valueContext() {}\n\nfunc NewLiteral_valueContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Literal_valueContext {\n\tvar p = new(Literal_valueContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_literal_value\n\n\treturn p\n}\n\nfunc (s *Literal_valueContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Literal_valueContext) NUMERIC_LITERAL() antlr.TerminalNode {\n\treturn s.GetToken(ParserNUMERIC_LITERAL, 0)\n}\n\nfunc (s *Literal_valueContext) STRING_LITERAL() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTRING_LITERAL, 0)\n}\n\nfunc (s *Literal_valueContext) BLOB_LITERAL() antlr.TerminalNode {\n\treturn s.GetToken(ParserBLOB_LITERAL, 0)\n}\n\nfunc (s *Literal_valueContext) NULL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNULL_, 0)\n}\n\nfunc (s *Literal_valueContext) TRUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTRUE_, 0)\n}\n\nfunc (s *Literal_valueContext) FALSE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFALSE_, 0)\n}\n\nfunc (s *Literal_valueContext) CURRENT_TIME_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_TIME_, 0)\n}\n\nfunc (s *Literal_valueContext) CURRENT_DATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_DATE_, 0)\n}\n\nfunc (s *Literal_valueContext) CURRENT_TIMESTAMP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_TIMESTAMP_, 0)\n}\n\nfunc (s *Literal_valueContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Literal_valueContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Literal_valueContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterLiteral_value(s)\n\t}\n}\n\nfunc (s *Literal_valueContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitLiteral_value(s)\n\t}\n}\n\nfunc (s *Literal_valueContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitLiteral_value(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Literal_value() (localctx ILiteral_valueContext) {\n\tlocalctx = NewLiteral_valueContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 68, ParserRULE_literal_value)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1096)\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif !(((int64((_la-52)) & ^0x3f) == 0 && ((int64(1)<<(_la-52))&4503599627370503) != 0) || ((int64((_la-172)) & ^0x3f) == 0 && ((int64(1)<<(_la-172))&212995) != 0)) {\n\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t} else {\n\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\tp.Consume()\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IInsert_stmtContext is an interface to support dynamic dispatch.\ntype IInsert_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tINTO_() antlr.TerminalNode\n\tTable_name() ITable_nameContext\n\tINSERT_() antlr.TerminalNode\n\tREPLACE_() antlr.TerminalNode\n\tOR_() antlr.TerminalNode\n\tDEFAULT_() antlr.TerminalNode\n\tVALUES_() antlr.TerminalNode\n\tWith_clause() IWith_clauseContext\n\tROLLBACK_() antlr.TerminalNode\n\tABORT_() antlr.TerminalNode\n\tFAIL_() antlr.TerminalNode\n\tIGNORE_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\tAS_() antlr.TerminalNode\n\tTable_alias() ITable_aliasContext\n\tAllOPEN_PAR() []antlr.TerminalNode\n\tOPEN_PAR(i int) antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tAllCLOSE_PAR() []antlr.TerminalNode\n\tCLOSE_PAR(i int) antlr.TerminalNode\n\tReturning_clause() IReturning_clauseContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tSelect_stmt() ISelect_stmtContext\n\tUpsert_clause() IUpsert_clauseContext\n\n\t// IsInsert_stmtContext differentiates from other interfaces.\n\tIsInsert_stmtContext()\n}\n\ntype Insert_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyInsert_stmtContext() *Insert_stmtContext {\n\tvar p = new(Insert_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_insert_stmt\n\treturn p\n}\n\nfunc InitEmptyInsert_stmtContext(p *Insert_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_insert_stmt\n}\n\nfunc (*Insert_stmtContext) IsInsert_stmtContext() {}\n\nfunc NewInsert_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Insert_stmtContext {\n\tvar p = new(Insert_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_insert_stmt\n\n\treturn p\n}\n\nfunc (s *Insert_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Insert_stmtContext) INTO_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINTO_, 0)\n}\n\nfunc (s *Insert_stmtContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Insert_stmtContext) INSERT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINSERT_, 0)\n}\n\nfunc (s *Insert_stmtContext) REPLACE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREPLACE_, 0)\n}\n\nfunc (s *Insert_stmtContext) OR_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOR_, 0)\n}\n\nfunc (s *Insert_stmtContext) DEFAULT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDEFAULT_, 0)\n}\n\nfunc (s *Insert_stmtContext) VALUES_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVALUES_, 0)\n}\n\nfunc (s *Insert_stmtContext) With_clause() IWith_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWith_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWith_clauseContext)\n}\n\nfunc (s *Insert_stmtContext) ROLLBACK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROLLBACK_, 0)\n}\n\nfunc (s *Insert_stmtContext) ABORT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserABORT_, 0)\n}\n\nfunc (s *Insert_stmtContext) FAIL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFAIL_, 0)\n}\n\nfunc (s *Insert_stmtContext) IGNORE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIGNORE_, 0)\n}\n\nfunc (s *Insert_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Insert_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Insert_stmtContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *Insert_stmtContext) Table_alias() ITable_aliasContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_aliasContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_aliasContext)\n}\n\nfunc (s *Insert_stmtContext) AllOPEN_PAR() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserOPEN_PAR)\n}\n\nfunc (s *Insert_stmtContext) OPEN_PAR(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, i)\n}\n\nfunc (s *Insert_stmtContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Insert_stmtContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Insert_stmtContext) AllCLOSE_PAR() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCLOSE_PAR)\n}\n\nfunc (s *Insert_stmtContext) CLOSE_PAR(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, i)\n}\n\nfunc (s *Insert_stmtContext) Returning_clause() IReturning_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IReturning_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IReturning_clauseContext)\n}\n\nfunc (s *Insert_stmtContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Insert_stmtContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Insert_stmtContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Insert_stmtContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Insert_stmtContext) Select_stmt() ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *Insert_stmtContext) Upsert_clause() IUpsert_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IUpsert_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IUpsert_clauseContext)\n}\n\nfunc (s *Insert_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Insert_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Insert_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterInsert_stmt(s)\n\t}\n}\n\nfunc (s *Insert_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitInsert_stmt(s)\n\t}\n}\n\nfunc (s *Insert_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitInsert_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Insert_stmt() (localctx IInsert_stmtContext) {\n\tlocalctx = NewInsert_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 70, ParserRULE_insert_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(1099)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWITH_ {\n\t\t{\n\t\t\tp.SetState(1098)\n\t\t\tp.With_clause()\n\t\t}\n\n\t}\n\tp.SetState(1106)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 139, p.GetParserRuleContext()) {\n\tcase 1:\n\t\t{\n\t\t\tp.SetState(1101)\n\t\t\tp.Match(ParserINSERT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 2:\n\t\t{\n\t\t\tp.SetState(1102)\n\t\t\tp.Match(ParserREPLACE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 3:\n\t\t{\n\t\t\tp.SetState(1103)\n\t\t\tp.Match(ParserINSERT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1104)\n\t\t\tp.Match(ParserOR_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1105)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserABORT_ || ((int64((_la-72)) & ^0x3f) == 0 && ((int64(1)<<(_la-72))&19140298416325121) != 0)) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1108)\n\t\tp.Match(ParserINTO_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1112)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 140, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(1109)\n\t\t\tp.Schema_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1110)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1114)\n\t\tp.Table_name()\n\t}\n\tp.SetState(1117)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserAS_ {\n\t\t{\n\t\t\tp.SetState(1115)\n\t\t\tp.Match(ParserAS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1116)\n\t\t\tp.Table_alias()\n\t\t}\n\n\t}\n\tp.SetState(1130)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserOPEN_PAR {\n\t\t{\n\t\t\tp.SetState(1119)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1120)\n\t\t\tp.Column_name()\n\t\t}\n\t\tp.SetState(1125)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1121)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1122)\n\t\t\t\tp.Column_name()\n\t\t\t}\n\n\t\t\tp.SetState(1127)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1128)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t}\n\tp.SetState(1168)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserSELECT_, ParserVALUES_, ParserWITH_:\n\t\tp.SetState(1161)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 147, p.GetParserRuleContext()) {\n\t\tcase 1:\n\t\t\t{\n\t\t\t\tp.SetState(1132)\n\t\t\t\tp.Match(ParserVALUES_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1133)\n\t\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1134)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\t\t\tp.SetState(1139)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1135)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1136)\n\t\t\t\t\tp.expr(0)\n\t\t\t\t}\n\n\t\t\t\tp.SetState(1141)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1142)\n\t\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.SetState(1157)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1143)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1144)\n\t\t\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1145)\n\t\t\t\t\tp.expr(0)\n\t\t\t\t}\n\t\t\t\tp.SetState(1150)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1146)\n\t\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1147)\n\t\t\t\t\t\tp.expr(0)\n\t\t\t\t\t}\n\n\t\t\t\t\tp.SetState(1152)\n\t\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1153)\n\t\t\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tp.SetState(1159)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\n\t\tcase 2:\n\t\t\t{\n\t\t\t\tp.SetState(1160)\n\t\t\t\tp.Select_stmt()\n\t\t\t}\n\n\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\tgoto errorExit\n\t\t}\n\t\tp.SetState(1164)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserON_ {\n\t\t\t{\n\t\t\t\tp.SetState(1163)\n\t\t\t\tp.Upsert_clause()\n\t\t\t}\n\n\t\t}\n\n\tcase ParserDEFAULT_:\n\t\t{\n\t\t\tp.SetState(1166)\n\t\t\tp.Match(ParserDEFAULT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1167)\n\t\t\tp.Match(ParserVALUES_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\tp.SetState(1171)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserRETURNING_ {\n\t\t{\n\t\t\tp.SetState(1170)\n\t\t\tp.Returning_clause()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IReturning_clauseContext is an interface to support dynamic dispatch.\ntype IReturning_clauseContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tRETURNING_() antlr.TerminalNode\n\tAllResult_column() []IResult_columnContext\n\tResult_column(i int) IResult_columnContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsReturning_clauseContext differentiates from other interfaces.\n\tIsReturning_clauseContext()\n}\n\ntype Returning_clauseContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyReturning_clauseContext() *Returning_clauseContext {\n\tvar p = new(Returning_clauseContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_returning_clause\n\treturn p\n}\n\nfunc InitEmptyReturning_clauseContext(p *Returning_clauseContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_returning_clause\n}\n\nfunc (*Returning_clauseContext) IsReturning_clauseContext() {}\n\nfunc NewReturning_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Returning_clauseContext {\n\tvar p = new(Returning_clauseContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_returning_clause\n\n\treturn p\n}\n\nfunc (s *Returning_clauseContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Returning_clauseContext) RETURNING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRETURNING_, 0)\n}\n\nfunc (s *Returning_clauseContext) AllResult_column() []IResult_columnContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IResult_columnContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IResult_columnContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IResult_columnContext); ok {\n\t\t\ttst[i] = t.(IResult_columnContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Returning_clauseContext) Result_column(i int) IResult_columnContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IResult_columnContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IResult_columnContext)\n}\n\nfunc (s *Returning_clauseContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Returning_clauseContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Returning_clauseContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Returning_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Returning_clauseContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterReturning_clause(s)\n\t}\n}\n\nfunc (s *Returning_clauseContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitReturning_clause(s)\n\t}\n}\n\nfunc (s *Returning_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitReturning_clause(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Returning_clause() (localctx IReturning_clauseContext) {\n\tlocalctx = NewReturning_clauseContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 72, ParserRULE_returning_clause)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1173)\n\t\tp.Match(ParserRETURNING_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1174)\n\t\tp.Result_column()\n\t}\n\tp.SetState(1179)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA {\n\t\t{\n\t\t\tp.SetState(1175)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1176)\n\t\t\tp.Result_column()\n\t\t}\n\n\t\tp.SetState(1181)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IUpsert_clauseContext is an interface to support dynamic dispatch.\ntype IUpsert_clauseContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tON_() antlr.TerminalNode\n\tCONFLICT_() antlr.TerminalNode\n\tDO_() antlr.TerminalNode\n\tNOTHING_() antlr.TerminalNode\n\tUPDATE_() antlr.TerminalNode\n\tSET_() antlr.TerminalNode\n\tOPEN_PAR() antlr.TerminalNode\n\tAllIndexed_column() []IIndexed_columnContext\n\tIndexed_column(i int) IIndexed_columnContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tAllASSIGN() []antlr.TerminalNode\n\tASSIGN(i int) antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\tAllWHERE_() []antlr.TerminalNode\n\tWHERE_(i int) antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tAllColumn_name_list() []IColumn_name_listContext\n\tColumn_name_list(i int) IColumn_name_listContext\n\n\t// IsUpsert_clauseContext differentiates from other interfaces.\n\tIsUpsert_clauseContext()\n}\n\ntype Upsert_clauseContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyUpsert_clauseContext() *Upsert_clauseContext {\n\tvar p = new(Upsert_clauseContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_upsert_clause\n\treturn p\n}\n\nfunc InitEmptyUpsert_clauseContext(p *Upsert_clauseContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_upsert_clause\n}\n\nfunc (*Upsert_clauseContext) IsUpsert_clauseContext() {}\n\nfunc NewUpsert_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Upsert_clauseContext {\n\tvar p = new(Upsert_clauseContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_upsert_clause\n\n\treturn p\n}\n\nfunc (s *Upsert_clauseContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Upsert_clauseContext) ON_() antlr.TerminalNode {\n\treturn s.GetToken(ParserON_, 0)\n}\n\nfunc (s *Upsert_clauseContext) CONFLICT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCONFLICT_, 0)\n}\n\nfunc (s *Upsert_clauseContext) DO_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDO_, 0)\n}\n\nfunc (s *Upsert_clauseContext) NOTHING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOTHING_, 0)\n}\n\nfunc (s *Upsert_clauseContext) UPDATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUPDATE_, 0)\n}\n\nfunc (s *Upsert_clauseContext) SET_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSET_, 0)\n}\n\nfunc (s *Upsert_clauseContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Upsert_clauseContext) AllIndexed_column() []IIndexed_columnContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IIndexed_columnContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IIndexed_columnContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IIndexed_columnContext); ok {\n\t\t\ttst[i] = t.(IIndexed_columnContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Upsert_clauseContext) Indexed_column(i int) IIndexed_columnContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IIndexed_columnContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IIndexed_columnContext)\n}\n\nfunc (s *Upsert_clauseContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Upsert_clauseContext) AllASSIGN() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserASSIGN)\n}\n\nfunc (s *Upsert_clauseContext) ASSIGN(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserASSIGN, i)\n}\n\nfunc (s *Upsert_clauseContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Upsert_clauseContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Upsert_clauseContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Upsert_clauseContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Upsert_clauseContext) AllWHERE_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserWHERE_)\n}\n\nfunc (s *Upsert_clauseContext) WHERE_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserWHERE_, i)\n}\n\nfunc (s *Upsert_clauseContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Upsert_clauseContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Upsert_clauseContext) AllColumn_name_list() []IColumn_name_listContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_name_listContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_name_listContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_name_listContext); ok {\n\t\t\ttst[i] = t.(IColumn_name_listContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Upsert_clauseContext) Column_name_list(i int) IColumn_name_listContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_name_listContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_name_listContext)\n}\n\nfunc (s *Upsert_clauseContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Upsert_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Upsert_clauseContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterUpsert_clause(s)\n\t}\n}\n\nfunc (s *Upsert_clauseContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitUpsert_clause(s)\n\t}\n}\n\nfunc (s *Upsert_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitUpsert_clause(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Upsert_clause() (localctx IUpsert_clauseContext) {\n\tlocalctx = NewUpsert_clauseContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 74, ParserRULE_upsert_clause)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1182)\n\t\tp.Match(ParserON_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1183)\n\t\tp.Match(ParserCONFLICT_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1198)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserOPEN_PAR {\n\t\t{\n\t\t\tp.SetState(1184)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1185)\n\t\t\tp.Indexed_column()\n\t\t}\n\t\tp.SetState(1190)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1186)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1187)\n\t\t\t\tp.Indexed_column()\n\t\t\t}\n\n\t\t\tp.SetState(1192)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1193)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1196)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserWHERE_ {\n\t\t\t{\n\t\t\t\tp.SetState(1194)\n\t\t\t\tp.Match(ParserWHERE_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1195)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(1200)\n\t\tp.Match(ParserDO_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1227)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserNOTHING_:\n\t\t{\n\t\t\tp.SetState(1201)\n\t\t\tp.Match(ParserNOTHING_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserUPDATE_:\n\t\t{\n\t\t\tp.SetState(1202)\n\t\t\tp.Match(ParserUPDATE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1203)\n\t\t\tp.Match(ParserSET_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t\tp.SetState(1206)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 155, p.GetParserRuleContext()) {\n\t\tcase 1:\n\t\t\t{\n\t\t\t\tp.SetState(1204)\n\t\t\t\tp.Column_name()\n\t\t\t}\n\n\t\tcase 2:\n\t\t\t{\n\t\t\t\tp.SetState(1205)\n\t\t\t\tp.Column_name_list()\n\t\t\t}\n\n\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(1208)\n\t\t\tp.Match(ParserASSIGN)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1209)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(1220)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1210)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.SetState(1213)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\n\t\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 156, p.GetParserRuleContext()) {\n\t\t\tcase 1:\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1211)\n\t\t\t\t\tp.Column_name()\n\t\t\t\t}\n\n\t\t\tcase 2:\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1212)\n\t\t\t\t\tp.Column_name_list()\n\t\t\t\t}\n\n\t\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1215)\n\t\t\t\tp.Match(ParserASSIGN)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1216)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t\tp.SetState(1222)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\tp.SetState(1225)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserWHERE_ {\n\t\t\t{\n\t\t\t\tp.SetState(1223)\n\t\t\t\tp.Match(ParserWHERE_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1224)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IPragma_stmtContext is an interface to support dynamic dispatch.\ntype IPragma_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tPRAGMA_() antlr.TerminalNode\n\tPragma_name() IPragma_nameContext\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\tASSIGN() antlr.TerminalNode\n\tPragma_value() IPragma_valueContext\n\tOPEN_PAR() antlr.TerminalNode\n\tCLOSE_PAR() antlr.TerminalNode\n\n\t// IsPragma_stmtContext differentiates from other interfaces.\n\tIsPragma_stmtContext()\n}\n\ntype Pragma_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyPragma_stmtContext() *Pragma_stmtContext {\n\tvar p = new(Pragma_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_pragma_stmt\n\treturn p\n}\n\nfunc InitEmptyPragma_stmtContext(p *Pragma_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_pragma_stmt\n}\n\nfunc (*Pragma_stmtContext) IsPragma_stmtContext() {}\n\nfunc NewPragma_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Pragma_stmtContext {\n\tvar p = new(Pragma_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_pragma_stmt\n\n\treturn p\n}\n\nfunc (s *Pragma_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Pragma_stmtContext) PRAGMA_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPRAGMA_, 0)\n}\n\nfunc (s *Pragma_stmtContext) Pragma_name() IPragma_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IPragma_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IPragma_nameContext)\n}\n\nfunc (s *Pragma_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Pragma_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Pragma_stmtContext) ASSIGN() antlr.TerminalNode {\n\treturn s.GetToken(ParserASSIGN, 0)\n}\n\nfunc (s *Pragma_stmtContext) Pragma_value() IPragma_valueContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IPragma_valueContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IPragma_valueContext)\n}\n\nfunc (s *Pragma_stmtContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Pragma_stmtContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Pragma_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Pragma_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Pragma_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterPragma_stmt(s)\n\t}\n}\n\nfunc (s *Pragma_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitPragma_stmt(s)\n\t}\n}\n\nfunc (s *Pragma_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitPragma_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Pragma_stmt() (localctx IPragma_stmtContext) {\n\tlocalctx = NewPragma_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 76, ParserRULE_pragma_stmt)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1229)\n\t\tp.Match(ParserPRAGMA_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1233)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 160, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(1230)\n\t\t\tp.Schema_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1231)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1235)\n\t\tp.Pragma_name()\n\t}\n\tp.SetState(1242)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserASSIGN:\n\t\t{\n\t\t\tp.SetState(1236)\n\t\t\tp.Match(ParserASSIGN)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1237)\n\t\t\tp.Pragma_value()\n\t\t}\n\n\tcase ParserOPEN_PAR:\n\t\t{\n\t\t\tp.SetState(1238)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1239)\n\t\t\tp.Pragma_value()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1240)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 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_:\n\n\tdefault:\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IPragma_valueContext is an interface to support dynamic dispatch.\ntype IPragma_valueContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tSigned_number() ISigned_numberContext\n\tName() INameContext\n\tSTRING_LITERAL() antlr.TerminalNode\n\n\t// IsPragma_valueContext differentiates from other interfaces.\n\tIsPragma_valueContext()\n}\n\ntype Pragma_valueContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyPragma_valueContext() *Pragma_valueContext {\n\tvar p = new(Pragma_valueContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_pragma_value\n\treturn p\n}\n\nfunc InitEmptyPragma_valueContext(p *Pragma_valueContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_pragma_value\n}\n\nfunc (*Pragma_valueContext) IsPragma_valueContext() {}\n\nfunc NewPragma_valueContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Pragma_valueContext {\n\tvar p = new(Pragma_valueContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_pragma_value\n\n\treturn p\n}\n\nfunc (s *Pragma_valueContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Pragma_valueContext) Signed_number() ISigned_numberContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISigned_numberContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISigned_numberContext)\n}\n\nfunc (s *Pragma_valueContext) Name() INameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(INameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(INameContext)\n}\n\nfunc (s *Pragma_valueContext) STRING_LITERAL() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTRING_LITERAL, 0)\n}\n\nfunc (s *Pragma_valueContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Pragma_valueContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Pragma_valueContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterPragma_value(s)\n\t}\n}\n\nfunc (s *Pragma_valueContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitPragma_value(s)\n\t}\n}\n\nfunc (s *Pragma_valueContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitPragma_value(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Pragma_value() (localctx IPragma_valueContext) {\n\tlocalctx = NewPragma_valueContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 78, ParserRULE_pragma_value)\n\tp.SetState(1247)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 162, p.GetParserRuleContext()) {\n\tcase 1:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(1244)\n\t\t\tp.Signed_number()\n\t\t}\n\n\tcase 2:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(1245)\n\t\t\tp.Name()\n\t\t}\n\n\tcase 3:\n\t\tp.EnterOuterAlt(localctx, 3)\n\t\t{\n\t\t\tp.SetState(1246)\n\t\t\tp.Match(ParserSTRING_LITERAL)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IReindex_stmtContext is an interface to support dynamic dispatch.\ntype IReindex_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tREINDEX_() antlr.TerminalNode\n\tCollation_name() ICollation_nameContext\n\tTable_name() ITable_nameContext\n\tIndex_name() IIndex_nameContext\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\n\t// IsReindex_stmtContext differentiates from other interfaces.\n\tIsReindex_stmtContext()\n}\n\ntype Reindex_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyReindex_stmtContext() *Reindex_stmtContext {\n\tvar p = new(Reindex_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_reindex_stmt\n\treturn p\n}\n\nfunc InitEmptyReindex_stmtContext(p *Reindex_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_reindex_stmt\n}\n\nfunc (*Reindex_stmtContext) IsReindex_stmtContext() {}\n\nfunc NewReindex_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Reindex_stmtContext {\n\tvar p = new(Reindex_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_reindex_stmt\n\n\treturn p\n}\n\nfunc (s *Reindex_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Reindex_stmtContext) REINDEX_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREINDEX_, 0)\n}\n\nfunc (s *Reindex_stmtContext) Collation_name() ICollation_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICollation_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICollation_nameContext)\n}\n\nfunc (s *Reindex_stmtContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Reindex_stmtContext) Index_name() IIndex_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IIndex_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IIndex_nameContext)\n}\n\nfunc (s *Reindex_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Reindex_stmtContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Reindex_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Reindex_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Reindex_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterReindex_stmt(s)\n\t}\n}\n\nfunc (s *Reindex_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitReindex_stmt(s)\n\t}\n}\n\nfunc (s *Reindex_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitReindex_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Reindex_stmt() (localctx IReindex_stmtContext) {\n\tlocalctx = NewReindex_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 80, ParserRULE_reindex_stmt)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1249)\n\t\tp.Match(ParserREINDEX_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1260)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 165, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(1250)\n\t\t\tp.Collation_name()\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t} else if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 165, p.GetParserRuleContext()) == 2 {\n\t\tp.SetState(1254)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 163, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(1251)\n\t\t\t\tp.Schema_name()\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1252)\n\t\t\t\tp.Match(ParserDOT)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\tp.SetState(1258)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 164, p.GetParserRuleContext()) {\n\t\tcase 1:\n\t\t\t{\n\t\t\t\tp.SetState(1256)\n\t\t\t\tp.Table_name()\n\t\t\t}\n\n\t\tcase 2:\n\t\t\t{\n\t\t\t\tp.SetState(1257)\n\t\t\t\tp.Index_name()\n\t\t\t}\n\n\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\tgoto errorExit\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISelect_stmtContext is an interface to support dynamic dispatch.\ntype ISelect_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAllSelect_core() []ISelect_coreContext\n\tSelect_core(i int) ISelect_coreContext\n\tCommon_table_stmt() ICommon_table_stmtContext\n\tAllCompound_operator() []ICompound_operatorContext\n\tCompound_operator(i int) ICompound_operatorContext\n\tOrder_by_stmt() IOrder_by_stmtContext\n\tLimit_stmt() ILimit_stmtContext\n\n\t// IsSelect_stmtContext differentiates from other interfaces.\n\tIsSelect_stmtContext()\n}\n\ntype Select_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySelect_stmtContext() *Select_stmtContext {\n\tvar p = new(Select_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_select_stmt\n\treturn p\n}\n\nfunc InitEmptySelect_stmtContext(p *Select_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_select_stmt\n}\n\nfunc (*Select_stmtContext) IsSelect_stmtContext() {}\n\nfunc NewSelect_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Select_stmtContext {\n\tvar p = new(Select_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_select_stmt\n\n\treturn p\n}\n\nfunc (s *Select_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Select_stmtContext) AllSelect_core() []ISelect_coreContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ISelect_coreContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ISelect_coreContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ISelect_coreContext); ok {\n\t\t\ttst[i] = t.(ISelect_coreContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Select_stmtContext) Select_core(i int) ISelect_coreContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_coreContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_coreContext)\n}\n\nfunc (s *Select_stmtContext) Common_table_stmt() ICommon_table_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICommon_table_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICommon_table_stmtContext)\n}\n\nfunc (s *Select_stmtContext) AllCompound_operator() []ICompound_operatorContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ICompound_operatorContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ICompound_operatorContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ICompound_operatorContext); ok {\n\t\t\ttst[i] = t.(ICompound_operatorContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Select_stmtContext) Compound_operator(i int) ICompound_operatorContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICompound_operatorContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICompound_operatorContext)\n}\n\nfunc (s *Select_stmtContext) Order_by_stmt() IOrder_by_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOrder_by_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOrder_by_stmtContext)\n}\n\nfunc (s *Select_stmtContext) Limit_stmt() ILimit_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ILimit_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ILimit_stmtContext)\n}\n\nfunc (s *Select_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Select_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Select_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSelect_stmt(s)\n\t}\n}\n\nfunc (s *Select_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSelect_stmt(s)\n\t}\n}\n\nfunc (s *Select_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSelect_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Select_stmt() (localctx ISelect_stmtContext) {\n\tlocalctx = NewSelect_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 82, ParserRULE_select_stmt)\n\tvar _la int\n\n\tvar _alt int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(1263)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWITH_ {\n\t\t{\n\t\t\tp.SetState(1262)\n\t\t\tp.Common_table_stmt()\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(1265)\n\t\tp.Select_core()\n\t}\n\tp.SetState(1271)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 167, p.GetParserRuleContext())\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\tfor _alt != 2 && _alt != antlr.ATNInvalidAltNumber {\n\t\tif _alt == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(1266)\n\t\t\t\tp.Compound_operator()\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1267)\n\t\t\t\tp.Select_core()\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(1273)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 167, p.GetParserRuleContext())\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1275)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserORDER_ {\n\t\t{\n\t\t\tp.SetState(1274)\n\t\t\tp.Order_by_stmt()\n\t\t}\n\n\t}\n\tp.SetState(1278)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserLIMIT_ {\n\t\t{\n\t\t\tp.SetState(1277)\n\t\t\tp.Limit_stmt()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IJoin_clauseContext is an interface to support dynamic dispatch.\ntype IJoin_clauseContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAllTable_or_subquery() []ITable_or_subqueryContext\n\tTable_or_subquery(i int) ITable_or_subqueryContext\n\tAllJoin_operator() []IJoin_operatorContext\n\tJoin_operator(i int) IJoin_operatorContext\n\tAllJoin_constraint() []IJoin_constraintContext\n\tJoin_constraint(i int) IJoin_constraintContext\n\n\t// IsJoin_clauseContext differentiates from other interfaces.\n\tIsJoin_clauseContext()\n}\n\ntype Join_clauseContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyJoin_clauseContext() *Join_clauseContext {\n\tvar p = new(Join_clauseContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_join_clause\n\treturn p\n}\n\nfunc InitEmptyJoin_clauseContext(p *Join_clauseContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_join_clause\n}\n\nfunc (*Join_clauseContext) IsJoin_clauseContext() {}\n\nfunc NewJoin_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Join_clauseContext {\n\tvar p = new(Join_clauseContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_join_clause\n\n\treturn p\n}\n\nfunc (s *Join_clauseContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Join_clauseContext) AllTable_or_subquery() []ITable_or_subqueryContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ITable_or_subqueryContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\ttst[i] = t.(ITable_or_subqueryContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Join_clauseContext) Table_or_subquery(i int) ITable_or_subqueryContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_or_subqueryContext)\n}\n\nfunc (s *Join_clauseContext) AllJoin_operator() []IJoin_operatorContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IJoin_operatorContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IJoin_operatorContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IJoin_operatorContext); ok {\n\t\t\ttst[i] = t.(IJoin_operatorContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Join_clauseContext) Join_operator(i int) IJoin_operatorContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IJoin_operatorContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IJoin_operatorContext)\n}\n\nfunc (s *Join_clauseContext) AllJoin_constraint() []IJoin_constraintContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IJoin_constraintContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IJoin_constraintContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IJoin_constraintContext); ok {\n\t\t\ttst[i] = t.(IJoin_constraintContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Join_clauseContext) Join_constraint(i int) IJoin_constraintContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IJoin_constraintContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IJoin_constraintContext)\n}\n\nfunc (s *Join_clauseContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Join_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Join_clauseContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterJoin_clause(s)\n\t}\n}\n\nfunc (s *Join_clauseContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitJoin_clause(s)\n\t}\n}\n\nfunc (s *Join_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitJoin_clause(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Join_clause() (localctx IJoin_clauseContext) {\n\tlocalctx = NewJoin_clauseContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 84, ParserRULE_join_clause)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1280)\n\t\tp.Table_or_subquery()\n\t}\n\tp.SetState(1288)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA || _la == ParserCROSS_ || ((int64((_la-87)) & ^0x3f) == 0 && ((int64(1)<<(_la-87))&8833) != 0) {\n\t\t{\n\t\t\tp.SetState(1281)\n\t\t\tp.Join_operator()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1282)\n\t\t\tp.Table_or_subquery()\n\t\t}\n\t\tp.SetState(1284)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 170, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(1283)\n\t\t\t\tp.Join_constraint()\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tp.SetState(1290)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISelect_coreContext is an interface to support dynamic dispatch.\ntype ISelect_coreContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tSELECT_() antlr.TerminalNode\n\tAllResult_column() []IResult_columnContext\n\tResult_column(i int) IResult_columnContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\tFROM_() antlr.TerminalNode\n\tWHERE_() antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tGROUP_() antlr.TerminalNode\n\tBY_() antlr.TerminalNode\n\tWINDOW_() antlr.TerminalNode\n\tAllWindow_name() []IWindow_nameContext\n\tWindow_name(i int) IWindow_nameContext\n\tAllAS_() []antlr.TerminalNode\n\tAS_(i int) antlr.TerminalNode\n\tAllWindow_defn() []IWindow_defnContext\n\tWindow_defn(i int) IWindow_defnContext\n\tDISTINCT_() antlr.TerminalNode\n\tALL_() antlr.TerminalNode\n\tAllTable_or_subquery() []ITable_or_subqueryContext\n\tTable_or_subquery(i int) ITable_or_subqueryContext\n\tJoin_clause() IJoin_clauseContext\n\tHAVING_() antlr.TerminalNode\n\tVALUES_() antlr.TerminalNode\n\tAllOPEN_PAR() []antlr.TerminalNode\n\tOPEN_PAR(i int) antlr.TerminalNode\n\tAllCLOSE_PAR() []antlr.TerminalNode\n\tCLOSE_PAR(i int) antlr.TerminalNode\n\n\t// IsSelect_coreContext differentiates from other interfaces.\n\tIsSelect_coreContext()\n}\n\ntype Select_coreContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySelect_coreContext() *Select_coreContext {\n\tvar p = new(Select_coreContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_select_core\n\treturn p\n}\n\nfunc InitEmptySelect_coreContext(p *Select_coreContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_select_core\n}\n\nfunc (*Select_coreContext) IsSelect_coreContext() {}\n\nfunc NewSelect_coreContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Select_coreContext {\n\tvar p = new(Select_coreContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_select_core\n\n\treturn p\n}\n\nfunc (s *Select_coreContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Select_coreContext) SELECT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSELECT_, 0)\n}\n\nfunc (s *Select_coreContext) AllResult_column() []IResult_columnContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IResult_columnContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IResult_columnContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IResult_columnContext); ok {\n\t\t\ttst[i] = t.(IResult_columnContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Select_coreContext) Result_column(i int) IResult_columnContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IResult_columnContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IResult_columnContext)\n}\n\nfunc (s *Select_coreContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Select_coreContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Select_coreContext) FROM_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFROM_, 0)\n}\n\nfunc (s *Select_coreContext) WHERE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWHERE_, 0)\n}\n\nfunc (s *Select_coreContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Select_coreContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Select_coreContext) GROUP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserGROUP_, 0)\n}\n\nfunc (s *Select_coreContext) BY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBY_, 0)\n}\n\nfunc (s *Select_coreContext) WINDOW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWINDOW_, 0)\n}\n\nfunc (s *Select_coreContext) AllWindow_name() []IWindow_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IWindow_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IWindow_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IWindow_nameContext); ok {\n\t\t\ttst[i] = t.(IWindow_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Select_coreContext) Window_name(i int) IWindow_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWindow_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWindow_nameContext)\n}\n\nfunc (s *Select_coreContext) AllAS_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserAS_)\n}\n\nfunc (s *Select_coreContext) AS_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, i)\n}\n\nfunc (s *Select_coreContext) AllWindow_defn() []IWindow_defnContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IWindow_defnContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IWindow_defnContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IWindow_defnContext); ok {\n\t\t\ttst[i] = t.(IWindow_defnContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Select_coreContext) Window_defn(i int) IWindow_defnContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWindow_defnContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWindow_defnContext)\n}\n\nfunc (s *Select_coreContext) DISTINCT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDISTINCT_, 0)\n}\n\nfunc (s *Select_coreContext) ALL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserALL_, 0)\n}\n\nfunc (s *Select_coreContext) AllTable_or_subquery() []ITable_or_subqueryContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ITable_or_subqueryContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\ttst[i] = t.(ITable_or_subqueryContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Select_coreContext) Table_or_subquery(i int) ITable_or_subqueryContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_or_subqueryContext)\n}\n\nfunc (s *Select_coreContext) Join_clause() IJoin_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IJoin_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IJoin_clauseContext)\n}\n\nfunc (s *Select_coreContext) HAVING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserHAVING_, 0)\n}\n\nfunc (s *Select_coreContext) VALUES_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVALUES_, 0)\n}\n\nfunc (s *Select_coreContext) AllOPEN_PAR() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserOPEN_PAR)\n}\n\nfunc (s *Select_coreContext) OPEN_PAR(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, i)\n}\n\nfunc (s *Select_coreContext) AllCLOSE_PAR() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCLOSE_PAR)\n}\n\nfunc (s *Select_coreContext) CLOSE_PAR(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, i)\n}\n\nfunc (s *Select_coreContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Select_coreContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Select_coreContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSelect_core(s)\n\t}\n}\n\nfunc (s *Select_coreContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSelect_core(s)\n\t}\n}\n\nfunc (s *Select_coreContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSelect_core(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Select_core() (localctx ISelect_coreContext) {\n\tlocalctx = NewSelect_coreContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 86, ParserRULE_select_core)\n\tvar _la int\n\n\tp.SetState(1381)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserSELECT_:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(1291)\n\t\t\tp.Match(ParserSELECT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1293)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 172, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(1292)\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\tif !(_la == ParserALL_ || _la == ParserDISTINCT_) {\n\t\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t\t} else {\n\t\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\t\tp.Consume()\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(1295)\n\t\t\tp.Result_column()\n\t\t}\n\t\tp.SetState(1300)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1296)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1297)\n\t\t\t\tp.Result_column()\n\t\t\t}\n\n\t\t\tp.SetState(1302)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\tp.SetState(1315)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserFROM_ {\n\t\t\t{\n\t\t\t\tp.SetState(1303)\n\t\t\t\tp.Match(ParserFROM_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.SetState(1313)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\n\t\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 175, p.GetParserRuleContext()) {\n\t\t\tcase 1:\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1304)\n\t\t\t\t\tp.Table_or_subquery()\n\t\t\t\t}\n\t\t\t\tp.SetState(1309)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1305)\n\t\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t{\n\t\t\t\t\t\tp.SetState(1306)\n\t\t\t\t\t\tp.Table_or_subquery()\n\t\t\t\t\t}\n\n\t\t\t\t\tp.SetState(1311)\n\t\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t\t}\n\n\t\t\tcase 2:\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1312)\n\t\t\t\t\tp.Join_clause()\n\t\t\t\t}\n\n\t\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\t\tgoto errorExit\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(1319)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserWHERE_ {\n\t\t\t{\n\t\t\t\tp.SetState(1317)\n\t\t\t\tp.Match(ParserWHERE_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1318)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(1335)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserGROUP_ {\n\t\t\t{\n\t\t\t\tp.SetState(1321)\n\t\t\t\tp.Match(ParserGROUP_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1322)\n\t\t\t\tp.Match(ParserBY_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1323)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\t\t\tp.SetState(1328)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1324)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1325)\n\t\t\t\t\tp.expr(0)\n\t\t\t\t}\n\n\t\t\t\tp.SetState(1330)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\t\t\tp.SetState(1333)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif _la == ParserHAVING_ {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1331)\n\t\t\t\t\tp.Match(ParserHAVING_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1332)\n\t\t\t\t\tp.expr(0)\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(1351)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserWINDOW_ {\n\t\t\t{\n\t\t\t\tp.SetState(1337)\n\t\t\t\tp.Match(ParserWINDOW_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1338)\n\t\t\t\tp.Window_name()\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1339)\n\t\t\t\tp.Match(ParserAS_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1340)\n\t\t\t\tp.Window_defn()\n\t\t\t}\n\t\t\tp.SetState(1348)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1341)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1342)\n\t\t\t\t\tp.Window_name()\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1343)\n\t\t\t\t\tp.Match(ParserAS_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1344)\n\t\t\t\t\tp.Window_defn()\n\t\t\t\t}\n\n\t\t\t\tp.SetState(1350)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\n\t\t}\n\n\tcase ParserVALUES_:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(1353)\n\t\t\tp.Match(ParserVALUES_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1354)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1355)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(1360)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1356)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1357)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t\tp.SetState(1362)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1363)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1378)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1364)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1365)\n\t\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1366)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\t\t\tp.SetState(1371)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1367)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1368)\n\t\t\t\t\tp.expr(0)\n\t\t\t\t}\n\n\t\t\t\tp.SetState(1373)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1374)\n\t\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tp.SetState(1380)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IFactored_select_stmtContext is an interface to support dynamic dispatch.\ntype IFactored_select_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tSelect_stmt() ISelect_stmtContext\n\n\t// IsFactored_select_stmtContext differentiates from other interfaces.\n\tIsFactored_select_stmtContext()\n}\n\ntype Factored_select_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyFactored_select_stmtContext() *Factored_select_stmtContext {\n\tvar p = new(Factored_select_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_factored_select_stmt\n\treturn p\n}\n\nfunc InitEmptyFactored_select_stmtContext(p *Factored_select_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_factored_select_stmt\n}\n\nfunc (*Factored_select_stmtContext) IsFactored_select_stmtContext() {}\n\nfunc NewFactored_select_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Factored_select_stmtContext {\n\tvar p = new(Factored_select_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_factored_select_stmt\n\n\treturn p\n}\n\nfunc (s *Factored_select_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Factored_select_stmtContext) Select_stmt() ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *Factored_select_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Factored_select_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Factored_select_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterFactored_select_stmt(s)\n\t}\n}\n\nfunc (s *Factored_select_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitFactored_select_stmt(s)\n\t}\n}\n\nfunc (s *Factored_select_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitFactored_select_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Factored_select_stmt() (localctx IFactored_select_stmtContext) {\n\tlocalctx = NewFactored_select_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 88, ParserRULE_factored_select_stmt)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1383)\n\t\tp.Select_stmt()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISimple_select_stmtContext is an interface to support dynamic dispatch.\ntype ISimple_select_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tSelect_core() ISelect_coreContext\n\tCommon_table_stmt() ICommon_table_stmtContext\n\tOrder_by_stmt() IOrder_by_stmtContext\n\tLimit_stmt() ILimit_stmtContext\n\n\t// IsSimple_select_stmtContext differentiates from other interfaces.\n\tIsSimple_select_stmtContext()\n}\n\ntype Simple_select_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySimple_select_stmtContext() *Simple_select_stmtContext {\n\tvar p = new(Simple_select_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_simple_select_stmt\n\treturn p\n}\n\nfunc InitEmptySimple_select_stmtContext(p *Simple_select_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_simple_select_stmt\n}\n\nfunc (*Simple_select_stmtContext) IsSimple_select_stmtContext() {}\n\nfunc NewSimple_select_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Simple_select_stmtContext {\n\tvar p = new(Simple_select_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_simple_select_stmt\n\n\treturn p\n}\n\nfunc (s *Simple_select_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Simple_select_stmtContext) Select_core() ISelect_coreContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_coreContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_coreContext)\n}\n\nfunc (s *Simple_select_stmtContext) Common_table_stmt() ICommon_table_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICommon_table_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICommon_table_stmtContext)\n}\n\nfunc (s *Simple_select_stmtContext) Order_by_stmt() IOrder_by_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOrder_by_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOrder_by_stmtContext)\n}\n\nfunc (s *Simple_select_stmtContext) Limit_stmt() ILimit_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ILimit_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ILimit_stmtContext)\n}\n\nfunc (s *Simple_select_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Simple_select_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Simple_select_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSimple_select_stmt(s)\n\t}\n}\n\nfunc (s *Simple_select_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSimple_select_stmt(s)\n\t}\n}\n\nfunc (s *Simple_select_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSimple_select_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Simple_select_stmt() (localctx ISimple_select_stmtContext) {\n\tlocalctx = NewSimple_select_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 90, ParserRULE_simple_select_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(1386)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWITH_ {\n\t\t{\n\t\t\tp.SetState(1385)\n\t\t\tp.Common_table_stmt()\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(1388)\n\t\tp.Select_core()\n\t}\n\tp.SetState(1390)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserORDER_ {\n\t\t{\n\t\t\tp.SetState(1389)\n\t\t\tp.Order_by_stmt()\n\t\t}\n\n\t}\n\tp.SetState(1393)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserLIMIT_ {\n\t\t{\n\t\t\tp.SetState(1392)\n\t\t\tp.Limit_stmt()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICompound_select_stmtContext is an interface to support dynamic dispatch.\ntype ICompound_select_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAllSelect_core() []ISelect_coreContext\n\tSelect_core(i int) ISelect_coreContext\n\tCommon_table_stmt() ICommon_table_stmtContext\n\tOrder_by_stmt() IOrder_by_stmtContext\n\tLimit_stmt() ILimit_stmtContext\n\tAllUNION_() []antlr.TerminalNode\n\tUNION_(i int) antlr.TerminalNode\n\tAllINTERSECT_() []antlr.TerminalNode\n\tINTERSECT_(i int) antlr.TerminalNode\n\tAllEXCEPT_() []antlr.TerminalNode\n\tEXCEPT_(i int) antlr.TerminalNode\n\tAllALL_() []antlr.TerminalNode\n\tALL_(i int) antlr.TerminalNode\n\n\t// IsCompound_select_stmtContext differentiates from other interfaces.\n\tIsCompound_select_stmtContext()\n}\n\ntype Compound_select_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCompound_select_stmtContext() *Compound_select_stmtContext {\n\tvar p = new(Compound_select_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_compound_select_stmt\n\treturn p\n}\n\nfunc InitEmptyCompound_select_stmtContext(p *Compound_select_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_compound_select_stmt\n}\n\nfunc (*Compound_select_stmtContext) IsCompound_select_stmtContext() {}\n\nfunc NewCompound_select_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Compound_select_stmtContext {\n\tvar p = new(Compound_select_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_compound_select_stmt\n\n\treturn p\n}\n\nfunc (s *Compound_select_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Compound_select_stmtContext) AllSelect_core() []ISelect_coreContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ISelect_coreContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ISelect_coreContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ISelect_coreContext); ok {\n\t\t\ttst[i] = t.(ISelect_coreContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Compound_select_stmtContext) Select_core(i int) ISelect_coreContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_coreContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_coreContext)\n}\n\nfunc (s *Compound_select_stmtContext) Common_table_stmt() ICommon_table_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICommon_table_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICommon_table_stmtContext)\n}\n\nfunc (s *Compound_select_stmtContext) Order_by_stmt() IOrder_by_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOrder_by_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOrder_by_stmtContext)\n}\n\nfunc (s *Compound_select_stmtContext) Limit_stmt() ILimit_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ILimit_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ILimit_stmtContext)\n}\n\nfunc (s *Compound_select_stmtContext) AllUNION_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserUNION_)\n}\n\nfunc (s *Compound_select_stmtContext) UNION_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserUNION_, i)\n}\n\nfunc (s *Compound_select_stmtContext) AllINTERSECT_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserINTERSECT_)\n}\n\nfunc (s *Compound_select_stmtContext) INTERSECT_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserINTERSECT_, i)\n}\n\nfunc (s *Compound_select_stmtContext) AllEXCEPT_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserEXCEPT_)\n}\n\nfunc (s *Compound_select_stmtContext) EXCEPT_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserEXCEPT_, i)\n}\n\nfunc (s *Compound_select_stmtContext) AllALL_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserALL_)\n}\n\nfunc (s *Compound_select_stmtContext) ALL_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserALL_, i)\n}\n\nfunc (s *Compound_select_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Compound_select_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Compound_select_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCompound_select_stmt(s)\n\t}\n}\n\nfunc (s *Compound_select_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCompound_select_stmt(s)\n\t}\n}\n\nfunc (s *Compound_select_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCompound_select_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Compound_select_stmt() (localctx ICompound_select_stmtContext) {\n\tlocalctx = NewCompound_select_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 92, ParserRULE_compound_select_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(1396)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWITH_ {\n\t\t{\n\t\t\tp.SetState(1395)\n\t\t\tp.Common_table_stmt()\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(1398)\n\t\tp.Select_core()\n\t}\n\tp.SetState(1408)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor ok := true; ok; ok = _la == ParserEXCEPT_ || _la == ParserINTERSECT_ || _la == ParserUNION_ {\n\t\tp.SetState(1405)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetTokenStream().LA(1) {\n\t\tcase ParserUNION_:\n\t\t\t{\n\t\t\t\tp.SetState(1399)\n\t\t\t\tp.Match(ParserUNION_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.SetState(1401)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif _la == ParserALL_ {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1400)\n\t\t\t\t\tp.Match(ParserALL_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\n\t\tcase ParserINTERSECT_:\n\t\t\t{\n\t\t\t\tp.SetState(1403)\n\t\t\t\tp.Match(ParserINTERSECT_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase ParserEXCEPT_:\n\t\t\t{\n\t\t\t\tp.SetState(1404)\n\t\t\t\tp.Match(ParserEXCEPT_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tdefault:\n\t\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(1407)\n\t\t\tp.Select_core()\n\t\t}\n\n\t\tp.SetState(1410)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\tp.SetState(1413)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserORDER_ {\n\t\t{\n\t\t\tp.SetState(1412)\n\t\t\tp.Order_by_stmt()\n\t\t}\n\n\t}\n\tp.SetState(1416)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserLIMIT_ {\n\t\t{\n\t\t\tp.SetState(1415)\n\t\t\tp.Limit_stmt()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ITable_or_subqueryContext is an interface to support dynamic dispatch.\ntype ITable_or_subqueryContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tTable_name() ITable_nameContext\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\tTable_alias() ITable_aliasContext\n\tINDEXED_() antlr.TerminalNode\n\tBY_() antlr.TerminalNode\n\tIndex_name() IIndex_nameContext\n\tNOT_() antlr.TerminalNode\n\tAS_() antlr.TerminalNode\n\tTable_function_name() ITable_function_nameContext\n\tOPEN_PAR() antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\tAllTable_or_subquery() []ITable_or_subqueryContext\n\tTable_or_subquery(i int) ITable_or_subqueryContext\n\tJoin_clause() IJoin_clauseContext\n\tSelect_stmt() ISelect_stmtContext\n\n\t// IsTable_or_subqueryContext differentiates from other interfaces.\n\tIsTable_or_subqueryContext()\n}\n\ntype Table_or_subqueryContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyTable_or_subqueryContext() *Table_or_subqueryContext {\n\tvar p = new(Table_or_subqueryContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_or_subquery\n\treturn p\n}\n\nfunc InitEmptyTable_or_subqueryContext(p *Table_or_subqueryContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_or_subquery\n}\n\nfunc (*Table_or_subqueryContext) IsTable_or_subqueryContext() {}\n\nfunc NewTable_or_subqueryContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_or_subqueryContext {\n\tvar p = new(Table_or_subqueryContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_table_or_subquery\n\n\treturn p\n}\n\nfunc (s *Table_or_subqueryContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Table_or_subqueryContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Table_or_subqueryContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Table_or_subqueryContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Table_or_subqueryContext) Table_alias() ITable_aliasContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_aliasContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_aliasContext)\n}\n\nfunc (s *Table_or_subqueryContext) INDEXED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINDEXED_, 0)\n}\n\nfunc (s *Table_or_subqueryContext) BY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBY_, 0)\n}\n\nfunc (s *Table_or_subqueryContext) Index_name() IIndex_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IIndex_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IIndex_nameContext)\n}\n\nfunc (s *Table_or_subqueryContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *Table_or_subqueryContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *Table_or_subqueryContext) Table_function_name() ITable_function_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_function_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_function_nameContext)\n}\n\nfunc (s *Table_or_subqueryContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Table_or_subqueryContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Table_or_subqueryContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Table_or_subqueryContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Table_or_subqueryContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Table_or_subqueryContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Table_or_subqueryContext) AllTable_or_subquery() []ITable_or_subqueryContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ITable_or_subqueryContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\ttst[i] = t.(ITable_or_subqueryContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Table_or_subqueryContext) Table_or_subquery(i int) ITable_or_subqueryContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_or_subqueryContext)\n}\n\nfunc (s *Table_or_subqueryContext) Join_clause() IJoin_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IJoin_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IJoin_clauseContext)\n}\n\nfunc (s *Table_or_subqueryContext) Select_stmt() ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *Table_or_subqueryContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Table_or_subqueryContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Table_or_subqueryContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterTable_or_subquery(s)\n\t}\n}\n\nfunc (s *Table_or_subqueryContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitTable_or_subquery(s)\n\t}\n}\n\nfunc (s *Table_or_subqueryContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitTable_or_subquery(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Table_or_subquery() (localctx ITable_or_subqueryContext) {\n\tlocalctx = NewTable_or_subqueryContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 94, ParserRULE_table_or_subquery)\n\tvar _la int\n\n\tp.SetState(1482)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 208, p.GetParserRuleContext()) {\n\tcase 1:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\tp.SetState(1421)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 196, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(1418)\n\t\t\t\tp.Schema_name()\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1419)\n\t\t\t\tp.Match(ParserDOT)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(1423)\n\t\t\tp.Table_name()\n\t\t}\n\t\tp.SetState(1428)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 198, p.GetParserRuleContext()) == 1 {\n\t\t\tp.SetState(1425)\n\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 197, p.GetParserRuleContext()) == 1 {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1424)\n\t\t\t\t\tp.Match(ParserAS_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else if p.HasError() { // JIM\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1427)\n\t\t\t\tp.Table_alias()\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\tp.SetState(1435)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\tswitch p.GetTokenStream().LA(1) {\n\t\tcase ParserINDEXED_:\n\t\t\t{\n\t\t\t\tp.SetState(1430)\n\t\t\t\tp.Match(ParserINDEXED_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1431)\n\t\t\t\tp.Match(ParserBY_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1432)\n\t\t\t\tp.Index_name()\n\t\t\t}\n\n\t\tcase ParserNOT_:\n\t\t\t{\n\t\t\t\tp.SetState(1433)\n\t\t\t\tp.Match(ParserNOT_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1434)\n\t\t\t\tp.Match(ParserINDEXED_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase 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_:\n\n\t\tdefault:\n\t\t}\n\n\tcase 2:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\tp.SetState(1440)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 200, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(1437)\n\t\t\t\tp.Schema_name()\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1438)\n\t\t\t\tp.Match(ParserDOT)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(1442)\n\t\t\tp.Table_function_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1443)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1444)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(1449)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1445)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1446)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t\tp.SetState(1451)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1452)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1457)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 203, p.GetParserRuleContext()) == 1 {\n\t\t\tp.SetState(1454)\n\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 202, p.GetParserRuleContext()) == 1 {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1453)\n\t\t\t\t\tp.Match(ParserAS_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else if p.HasError() { // JIM\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1456)\n\t\t\t\tp.Table_alias()\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\n\tcase 3:\n\t\tp.EnterOuterAlt(localctx, 3)\n\t\t{\n\t\t\tp.SetState(1459)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1469)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 205, p.GetParserRuleContext()) {\n\t\tcase 1:\n\t\t\t{\n\t\t\t\tp.SetState(1460)\n\t\t\t\tp.Table_or_subquery()\n\t\t\t}\n\t\t\tp.SetState(1465)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1461)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1462)\n\t\t\t\t\tp.Table_or_subquery()\n\t\t\t\t}\n\n\t\t\t\tp.SetState(1467)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\n\t\tcase 2:\n\t\t\t{\n\t\t\t\tp.SetState(1468)\n\t\t\t\tp.Join_clause()\n\t\t\t}\n\n\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(1471)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 4:\n\t\tp.EnterOuterAlt(localctx, 4)\n\t\t{\n\t\t\tp.SetState(1473)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1474)\n\t\t\tp.Select_stmt()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1475)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1480)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 207, p.GetParserRuleContext()) == 1 {\n\t\t\tp.SetState(1477)\n\t\t\tp.GetErrorHandler().Sync(p)\n\n\t\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 206, p.GetParserRuleContext()) == 1 {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1476)\n\t\t\t\t\tp.Match(ParserAS_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else if p.HasError() { // JIM\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1479)\n\t\t\t\tp.Table_alias()\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IResult_columnContext is an interface to support dynamic dispatch.\ntype IResult_columnContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tSTAR() antlr.TerminalNode\n\tTable_name() ITable_nameContext\n\tDOT() antlr.TerminalNode\n\tExpr() IExprContext\n\tColumn_alias() IColumn_aliasContext\n\tAS_() antlr.TerminalNode\n\n\t// IsResult_columnContext differentiates from other interfaces.\n\tIsResult_columnContext()\n}\n\ntype Result_columnContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyResult_columnContext() *Result_columnContext {\n\tvar p = new(Result_columnContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_result_column\n\treturn p\n}\n\nfunc InitEmptyResult_columnContext(p *Result_columnContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_result_column\n}\n\nfunc (*Result_columnContext) IsResult_columnContext() {}\n\nfunc NewResult_columnContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Result_columnContext {\n\tvar p = new(Result_columnContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_result_column\n\n\treturn p\n}\n\nfunc (s *Result_columnContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Result_columnContext) STAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTAR, 0)\n}\n\nfunc (s *Result_columnContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Result_columnContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Result_columnContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Result_columnContext) Column_alias() IColumn_aliasContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_aliasContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_aliasContext)\n}\n\nfunc (s *Result_columnContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *Result_columnContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Result_columnContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Result_columnContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterResult_column(s)\n\t}\n}\n\nfunc (s *Result_columnContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitResult_column(s)\n\t}\n}\n\nfunc (s *Result_columnContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitResult_column(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Result_column() (localctx IResult_columnContext) {\n\tlocalctx = NewResult_columnContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 96, ParserRULE_result_column)\n\tvar _la int\n\n\tp.SetState(1496)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 211, p.GetParserRuleContext()) {\n\tcase 1:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(1484)\n\t\t\tp.Match(ParserSTAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 2:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(1485)\n\t\t\tp.Table_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1486)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1487)\n\t\t\tp.Match(ParserSTAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 3:\n\t\tp.EnterOuterAlt(localctx, 3)\n\t\t{\n\t\t\tp.SetState(1489)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(1494)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserAS_ || _la == ParserIDENTIFIER || _la == ParserSTRING_LITERAL {\n\t\t\tp.SetState(1491)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif _la == ParserAS_ {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1490)\n\t\t\t\t\tp.Match(ParserAS_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1493)\n\t\t\t\tp.Column_alias()\n\t\t\t}\n\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IJoin_operatorContext is an interface to support dynamic dispatch.\ntype IJoin_operatorContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tCOMMA() antlr.TerminalNode\n\tJOIN_() antlr.TerminalNode\n\tNATURAL_() antlr.TerminalNode\n\tLEFT_() antlr.TerminalNode\n\tINNER_() antlr.TerminalNode\n\tCROSS_() antlr.TerminalNode\n\tOUTER_() antlr.TerminalNode\n\n\t// IsJoin_operatorContext differentiates from other interfaces.\n\tIsJoin_operatorContext()\n}\n\ntype Join_operatorContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyJoin_operatorContext() *Join_operatorContext {\n\tvar p = new(Join_operatorContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_join_operator\n\treturn p\n}\n\nfunc InitEmptyJoin_operatorContext(p *Join_operatorContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_join_operator\n}\n\nfunc (*Join_operatorContext) IsJoin_operatorContext() {}\n\nfunc NewJoin_operatorContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Join_operatorContext {\n\tvar p = new(Join_operatorContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_join_operator\n\n\treturn p\n}\n\nfunc (s *Join_operatorContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Join_operatorContext) COMMA() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, 0)\n}\n\nfunc (s *Join_operatorContext) JOIN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserJOIN_, 0)\n}\n\nfunc (s *Join_operatorContext) NATURAL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNATURAL_, 0)\n}\n\nfunc (s *Join_operatorContext) LEFT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLEFT_, 0)\n}\n\nfunc (s *Join_operatorContext) INNER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINNER_, 0)\n}\n\nfunc (s *Join_operatorContext) CROSS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCROSS_, 0)\n}\n\nfunc (s *Join_operatorContext) OUTER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOUTER_, 0)\n}\n\nfunc (s *Join_operatorContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Join_operatorContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Join_operatorContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterJoin_operator(s)\n\t}\n}\n\nfunc (s *Join_operatorContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitJoin_operator(s)\n\t}\n}\n\nfunc (s *Join_operatorContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitJoin_operator(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Join_operator() (localctx IJoin_operatorContext) {\n\tlocalctx = NewJoin_operatorContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 98, ParserRULE_join_operator)\n\tvar _la int\n\n\tp.SetState(1511)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserCOMMA:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(1498)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserCROSS_, ParserINNER_, ParserJOIN_, ParserLEFT_, ParserNATURAL_:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\tp.SetState(1500)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserNATURAL_ {\n\t\t\t{\n\t\t\t\tp.SetState(1499)\n\t\t\t\tp.Match(ParserNATURAL_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(1508)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\tswitch p.GetTokenStream().LA(1) {\n\t\tcase ParserLEFT_:\n\t\t\t{\n\t\t\t\tp.SetState(1502)\n\t\t\t\tp.Match(ParserLEFT_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.SetState(1504)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif _la == ParserOUTER_ {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1503)\n\t\t\t\t\tp.Match(ParserOUTER_)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\n\t\tcase ParserINNER_:\n\t\t\t{\n\t\t\t\tp.SetState(1506)\n\t\t\t\tp.Match(ParserINNER_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase ParserCROSS_:\n\t\t\t{\n\t\t\t\tp.SetState(1507)\n\t\t\t\tp.Match(ParserCROSS_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase ParserJOIN_:\n\n\t\tdefault:\n\t\t}\n\t\t{\n\t\t\tp.SetState(1510)\n\t\t\tp.Match(ParserJOIN_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IJoin_constraintContext is an interface to support dynamic dispatch.\ntype IJoin_constraintContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tON_() antlr.TerminalNode\n\tExpr() IExprContext\n\tUSING_() antlr.TerminalNode\n\tOPEN_PAR() antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsJoin_constraintContext differentiates from other interfaces.\n\tIsJoin_constraintContext()\n}\n\ntype Join_constraintContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyJoin_constraintContext() *Join_constraintContext {\n\tvar p = new(Join_constraintContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_join_constraint\n\treturn p\n}\n\nfunc InitEmptyJoin_constraintContext(p *Join_constraintContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_join_constraint\n}\n\nfunc (*Join_constraintContext) IsJoin_constraintContext() {}\n\nfunc NewJoin_constraintContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Join_constraintContext {\n\tvar p = new(Join_constraintContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_join_constraint\n\n\treturn p\n}\n\nfunc (s *Join_constraintContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Join_constraintContext) ON_() antlr.TerminalNode {\n\treturn s.GetToken(ParserON_, 0)\n}\n\nfunc (s *Join_constraintContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Join_constraintContext) USING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUSING_, 0)\n}\n\nfunc (s *Join_constraintContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Join_constraintContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Join_constraintContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Join_constraintContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Join_constraintContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Join_constraintContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Join_constraintContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Join_constraintContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Join_constraintContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterJoin_constraint(s)\n\t}\n}\n\nfunc (s *Join_constraintContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitJoin_constraint(s)\n\t}\n}\n\nfunc (s *Join_constraintContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitJoin_constraint(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Join_constraint() (localctx IJoin_constraintContext) {\n\tlocalctx = NewJoin_constraintContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 100, ParserRULE_join_constraint)\n\tvar _la int\n\n\tp.SetState(1527)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserON_:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(1513)\n\t\t\tp.Match(ParserON_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1514)\n\t\t\tp.expr(0)\n\t\t}\n\n\tcase ParserUSING_:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(1515)\n\t\t\tp.Match(ParserUSING_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1516)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1517)\n\t\t\tp.Column_name()\n\t\t}\n\t\tp.SetState(1522)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1518)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1519)\n\t\t\t\tp.Column_name()\n\t\t\t}\n\n\t\t\tp.SetState(1524)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1525)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICompound_operatorContext is an interface to support dynamic dispatch.\ntype ICompound_operatorContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tUNION_() antlr.TerminalNode\n\tALL_() antlr.TerminalNode\n\tINTERSECT_() antlr.TerminalNode\n\tEXCEPT_() antlr.TerminalNode\n\n\t// IsCompound_operatorContext differentiates from other interfaces.\n\tIsCompound_operatorContext()\n}\n\ntype Compound_operatorContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCompound_operatorContext() *Compound_operatorContext {\n\tvar p = new(Compound_operatorContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_compound_operator\n\treturn p\n}\n\nfunc InitEmptyCompound_operatorContext(p *Compound_operatorContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_compound_operator\n}\n\nfunc (*Compound_operatorContext) IsCompound_operatorContext() {}\n\nfunc NewCompound_operatorContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Compound_operatorContext {\n\tvar p = new(Compound_operatorContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_compound_operator\n\n\treturn p\n}\n\nfunc (s *Compound_operatorContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Compound_operatorContext) UNION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNION_, 0)\n}\n\nfunc (s *Compound_operatorContext) ALL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserALL_, 0)\n}\n\nfunc (s *Compound_operatorContext) INTERSECT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINTERSECT_, 0)\n}\n\nfunc (s *Compound_operatorContext) EXCEPT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXCEPT_, 0)\n}\n\nfunc (s *Compound_operatorContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Compound_operatorContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Compound_operatorContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCompound_operator(s)\n\t}\n}\n\nfunc (s *Compound_operatorContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCompound_operator(s)\n\t}\n}\n\nfunc (s *Compound_operatorContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCompound_operator(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Compound_operator() (localctx ICompound_operatorContext) {\n\tlocalctx = NewCompound_operatorContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 102, ParserRULE_compound_operator)\n\tvar _la int\n\n\tp.SetState(1535)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserUNION_:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(1529)\n\t\t\tp.Match(ParserUNION_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1531)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserALL_ {\n\t\t\t{\n\t\t\t\tp.SetState(1530)\n\t\t\t\tp.Match(ParserALL_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tcase ParserINTERSECT_:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(1533)\n\t\t\tp.Match(ParserINTERSECT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserEXCEPT_:\n\t\tp.EnterOuterAlt(localctx, 3)\n\t\t{\n\t\t\tp.SetState(1534)\n\t\t\tp.Match(ParserEXCEPT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IUpdate_stmtContext is an interface to support dynamic dispatch.\ntype IUpdate_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// GetWhere returns the where rule contexts.\n\tGetWhere() IExprContext\n\n\t// SetWhere sets the where rule contexts.\n\tSetWhere(IExprContext)\n\n\t// Getter signatures\n\tUPDATE_() antlr.TerminalNode\n\tQualified_table_name() IQualified_table_nameContext\n\tSET_() antlr.TerminalNode\n\tAssignment_list() IAssignment_listContext\n\tWith_clause() IWith_clauseContext\n\tOR_() antlr.TerminalNode\n\tFROM_() antlr.TerminalNode\n\tWHERE_() antlr.TerminalNode\n\tReturning_clause() IReturning_clauseContext\n\tROLLBACK_() antlr.TerminalNode\n\tABORT_() antlr.TerminalNode\n\tREPLACE_() antlr.TerminalNode\n\tFAIL_() antlr.TerminalNode\n\tIGNORE_() antlr.TerminalNode\n\tExpr() IExprContext\n\tAllTable_or_subquery() []ITable_or_subqueryContext\n\tTable_or_subquery(i int) ITable_or_subqueryContext\n\tJoin_clause() IJoin_clauseContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsUpdate_stmtContext differentiates from other interfaces.\n\tIsUpdate_stmtContext()\n}\n\ntype Update_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n\twhere  IExprContext\n}\n\nfunc NewEmptyUpdate_stmtContext() *Update_stmtContext {\n\tvar p = new(Update_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_update_stmt\n\treturn p\n}\n\nfunc InitEmptyUpdate_stmtContext(p *Update_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_update_stmt\n}\n\nfunc (*Update_stmtContext) IsUpdate_stmtContext() {}\n\nfunc NewUpdate_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Update_stmtContext {\n\tvar p = new(Update_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_update_stmt\n\n\treturn p\n}\n\nfunc (s *Update_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Update_stmtContext) GetWhere() IExprContext { return s.where }\n\nfunc (s *Update_stmtContext) SetWhere(v IExprContext) { s.where = v }\n\nfunc (s *Update_stmtContext) UPDATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUPDATE_, 0)\n}\n\nfunc (s *Update_stmtContext) Qualified_table_name() IQualified_table_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IQualified_table_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IQualified_table_nameContext)\n}\n\nfunc (s *Update_stmtContext) SET_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSET_, 0)\n}\n\nfunc (s *Update_stmtContext) Assignment_list() IAssignment_listContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAssignment_listContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAssignment_listContext)\n}\n\nfunc (s *Update_stmtContext) With_clause() IWith_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWith_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWith_clauseContext)\n}\n\nfunc (s *Update_stmtContext) OR_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOR_, 0)\n}\n\nfunc (s *Update_stmtContext) FROM_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFROM_, 0)\n}\n\nfunc (s *Update_stmtContext) WHERE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWHERE_, 0)\n}\n\nfunc (s *Update_stmtContext) Returning_clause() IReturning_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IReturning_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IReturning_clauseContext)\n}\n\nfunc (s *Update_stmtContext) ROLLBACK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROLLBACK_, 0)\n}\n\nfunc (s *Update_stmtContext) ABORT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserABORT_, 0)\n}\n\nfunc (s *Update_stmtContext) REPLACE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREPLACE_, 0)\n}\n\nfunc (s *Update_stmtContext) FAIL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFAIL_, 0)\n}\n\nfunc (s *Update_stmtContext) IGNORE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIGNORE_, 0)\n}\n\nfunc (s *Update_stmtContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Update_stmtContext) AllTable_or_subquery() []ITable_or_subqueryContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ITable_or_subqueryContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\ttst[i] = t.(ITable_or_subqueryContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Update_stmtContext) Table_or_subquery(i int) ITable_or_subqueryContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_or_subqueryContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_or_subqueryContext)\n}\n\nfunc (s *Update_stmtContext) Join_clause() IJoin_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IJoin_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IJoin_clauseContext)\n}\n\nfunc (s *Update_stmtContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Update_stmtContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Update_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Update_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Update_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterUpdate_stmt(s)\n\t}\n}\n\nfunc (s *Update_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitUpdate_stmt(s)\n\t}\n}\n\nfunc (s *Update_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitUpdate_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Update_stmt() (localctx IUpdate_stmtContext) {\n\tlocalctx = NewUpdate_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 104, ParserRULE_update_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(1538)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWITH_ {\n\t\t{\n\t\t\tp.SetState(1537)\n\t\t\tp.With_clause()\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(1540)\n\t\tp.Match(ParserUPDATE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1543)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 221, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(1541)\n\t\t\tp.Match(ParserOR_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1542)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserABORT_ || ((int64((_la-72)) & ^0x3f) == 0 && ((int64(1)<<(_la-72))&19140298416325121) != 0)) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1545)\n\t\tp.Qualified_table_name()\n\t}\n\t{\n\t\tp.SetState(1546)\n\t\tp.Match(ParserSET_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1547)\n\t\tp.Assignment_list()\n\t}\n\tp.SetState(1560)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserFROM_ {\n\t\t{\n\t\t\tp.SetState(1548)\n\t\t\tp.Match(ParserFROM_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1558)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 223, p.GetParserRuleContext()) {\n\t\tcase 1:\n\t\t\t{\n\t\t\t\tp.SetState(1549)\n\t\t\t\tp.Table_or_subquery()\n\t\t\t}\n\t\t\tp.SetState(1554)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1550)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1551)\n\t\t\t\t\tp.Table_or_subquery()\n\t\t\t\t}\n\n\t\t\t\tp.SetState(1556)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\n\t\tcase 2:\n\t\t\t{\n\t\t\t\tp.SetState(1557)\n\t\t\t\tp.Join_clause()\n\t\t\t}\n\n\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\tgoto errorExit\n\t\t}\n\n\t}\n\tp.SetState(1564)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWHERE_ {\n\t\t{\n\t\t\tp.SetState(1562)\n\t\t\tp.Match(ParserWHERE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1563)\n\n\t\t\tvar _x = p.expr(0)\n\n\t\t\tlocalctx.(*Update_stmtContext).where = _x\n\t\t}\n\n\t}\n\tp.SetState(1567)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserRETURNING_ {\n\t\t{\n\t\t\tp.SetState(1566)\n\t\t\tp.Returning_clause()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IAssignment_listContext is an interface to support dynamic dispatch.\ntype IAssignment_listContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAllAssignment() []IAssignmentContext\n\tAssignment(i int) IAssignmentContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsAssignment_listContext differentiates from other interfaces.\n\tIsAssignment_listContext()\n}\n\ntype Assignment_listContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyAssignment_listContext() *Assignment_listContext {\n\tvar p = new(Assignment_listContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_assignment_list\n\treturn p\n}\n\nfunc InitEmptyAssignment_listContext(p *Assignment_listContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_assignment_list\n}\n\nfunc (*Assignment_listContext) IsAssignment_listContext() {}\n\nfunc NewAssignment_listContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Assignment_listContext {\n\tvar p = new(Assignment_listContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_assignment_list\n\n\treturn p\n}\n\nfunc (s *Assignment_listContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Assignment_listContext) AllAssignment() []IAssignmentContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IAssignmentContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IAssignmentContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IAssignmentContext); ok {\n\t\t\ttst[i] = t.(IAssignmentContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Assignment_listContext) Assignment(i int) IAssignmentContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAssignmentContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAssignmentContext)\n}\n\nfunc (s *Assignment_listContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Assignment_listContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Assignment_listContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Assignment_listContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Assignment_listContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterAssignment_list(s)\n\t}\n}\n\nfunc (s *Assignment_listContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitAssignment_list(s)\n\t}\n}\n\nfunc (s *Assignment_listContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitAssignment_list(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Assignment_list() (localctx IAssignment_listContext) {\n\tlocalctx = NewAssignment_listContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 106, ParserRULE_assignment_list)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1569)\n\t\tp.Assignment()\n\t}\n\tp.SetState(1574)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA {\n\t\t{\n\t\t\tp.SetState(1570)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1571)\n\t\t\tp.Assignment()\n\t\t}\n\n\t\tp.SetState(1576)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IAssignmentContext is an interface to support dynamic dispatch.\ntype IAssignmentContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tASSIGN() antlr.TerminalNode\n\tExpr() IExprContext\n\tColumn_name() IColumn_nameContext\n\tColumn_name_list() IColumn_name_listContext\n\n\t// IsAssignmentContext differentiates from other interfaces.\n\tIsAssignmentContext()\n}\n\ntype AssignmentContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyAssignmentContext() *AssignmentContext {\n\tvar p = new(AssignmentContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_assignment\n\treturn p\n}\n\nfunc InitEmptyAssignmentContext(p *AssignmentContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_assignment\n}\n\nfunc (*AssignmentContext) IsAssignmentContext() {}\n\nfunc NewAssignmentContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *AssignmentContext {\n\tvar p = new(AssignmentContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_assignment\n\n\treturn p\n}\n\nfunc (s *AssignmentContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *AssignmentContext) ASSIGN() antlr.TerminalNode {\n\treturn s.GetToken(ParserASSIGN, 0)\n}\n\nfunc (s *AssignmentContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *AssignmentContext) Column_name() IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *AssignmentContext) Column_name_list() IColumn_name_listContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_name_listContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_name_listContext)\n}\n\nfunc (s *AssignmentContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *AssignmentContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *AssignmentContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterAssignment(s)\n\t}\n}\n\nfunc (s *AssignmentContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitAssignment(s)\n\t}\n}\n\nfunc (s *AssignmentContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitAssignment(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Assignment() (localctx IAssignmentContext) {\n\tlocalctx = NewAssignmentContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 108, ParserRULE_assignment)\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(1579)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 228, p.GetParserRuleContext()) {\n\tcase 1:\n\t\t{\n\t\t\tp.SetState(1577)\n\t\t\tp.Column_name()\n\t\t}\n\n\tcase 2:\n\t\t{\n\t\t\tp.SetState(1578)\n\t\t\tp.Column_name_list()\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1581)\n\t\tp.Match(ParserASSIGN)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1582)\n\t\tp.expr(0)\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IColumn_name_listContext is an interface to support dynamic dispatch.\ntype IColumn_name_listContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tOPEN_PAR() antlr.TerminalNode\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tCLOSE_PAR() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsColumn_name_listContext differentiates from other interfaces.\n\tIsColumn_name_listContext()\n}\n\ntype Column_name_listContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyColumn_name_listContext() *Column_name_listContext {\n\tvar p = new(Column_name_listContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_column_name_list\n\treturn p\n}\n\nfunc InitEmptyColumn_name_listContext(p *Column_name_listContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_column_name_list\n}\n\nfunc (*Column_name_listContext) IsColumn_name_listContext() {}\n\nfunc NewColumn_name_listContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Column_name_listContext {\n\tvar p = new(Column_name_listContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_column_name_list\n\n\treturn p\n}\n\nfunc (s *Column_name_listContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Column_name_listContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Column_name_listContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Column_name_listContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Column_name_listContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Column_name_listContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Column_name_listContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Column_name_listContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Column_name_listContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Column_name_listContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterColumn_name_list(s)\n\t}\n}\n\nfunc (s *Column_name_listContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitColumn_name_list(s)\n\t}\n}\n\nfunc (s *Column_name_listContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitColumn_name_list(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Column_name_list() (localctx IColumn_name_listContext) {\n\tlocalctx = NewColumn_name_listContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 110, ParserRULE_column_name_list)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1584)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1585)\n\t\tp.Column_name()\n\t}\n\tp.SetState(1590)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA {\n\t\t{\n\t\t\tp.SetState(1586)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1587)\n\t\t\tp.Column_name()\n\t\t}\n\n\t\tp.SetState(1592)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\t{\n\t\tp.SetState(1593)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IUpdate_stmt_limitedContext is an interface to support dynamic dispatch.\ntype IUpdate_stmt_limitedContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tUPDATE_() antlr.TerminalNode\n\tQualified_table_name() IQualified_table_nameContext\n\tSET_() antlr.TerminalNode\n\tAllASSIGN() []antlr.TerminalNode\n\tASSIGN(i int) antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tAllColumn_name() []IColumn_nameContext\n\tColumn_name(i int) IColumn_nameContext\n\tAllColumn_name_list() []IColumn_name_listContext\n\tColumn_name_list(i int) IColumn_name_listContext\n\tWith_clause() IWith_clauseContext\n\tOR_() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\tWHERE_() antlr.TerminalNode\n\tReturning_clause() IReturning_clauseContext\n\tLimit_stmt() ILimit_stmtContext\n\tROLLBACK_() antlr.TerminalNode\n\tABORT_() antlr.TerminalNode\n\tREPLACE_() antlr.TerminalNode\n\tFAIL_() antlr.TerminalNode\n\tIGNORE_() antlr.TerminalNode\n\tOrder_by_stmt() IOrder_by_stmtContext\n\n\t// IsUpdate_stmt_limitedContext differentiates from other interfaces.\n\tIsUpdate_stmt_limitedContext()\n}\n\ntype Update_stmt_limitedContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyUpdate_stmt_limitedContext() *Update_stmt_limitedContext {\n\tvar p = new(Update_stmt_limitedContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_update_stmt_limited\n\treturn p\n}\n\nfunc InitEmptyUpdate_stmt_limitedContext(p *Update_stmt_limitedContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_update_stmt_limited\n}\n\nfunc (*Update_stmt_limitedContext) IsUpdate_stmt_limitedContext() {}\n\nfunc NewUpdate_stmt_limitedContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Update_stmt_limitedContext {\n\tvar p = new(Update_stmt_limitedContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_update_stmt_limited\n\n\treturn p\n}\n\nfunc (s *Update_stmt_limitedContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Update_stmt_limitedContext) UPDATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUPDATE_, 0)\n}\n\nfunc (s *Update_stmt_limitedContext) Qualified_table_name() IQualified_table_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IQualified_table_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IQualified_table_nameContext)\n}\n\nfunc (s *Update_stmt_limitedContext) SET_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSET_, 0)\n}\n\nfunc (s *Update_stmt_limitedContext) AllASSIGN() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserASSIGN)\n}\n\nfunc (s *Update_stmt_limitedContext) ASSIGN(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserASSIGN, i)\n}\n\nfunc (s *Update_stmt_limitedContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Update_stmt_limitedContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Update_stmt_limitedContext) AllColumn_name() []IColumn_nameContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_nameContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_nameContext); ok {\n\t\t\ttst[i] = t.(IColumn_nameContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Update_stmt_limitedContext) Column_name(i int) IColumn_nameContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_nameContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_nameContext)\n}\n\nfunc (s *Update_stmt_limitedContext) AllColumn_name_list() []IColumn_name_listContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IColumn_name_listContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IColumn_name_listContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IColumn_name_listContext); ok {\n\t\t\ttst[i] = t.(IColumn_name_listContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Update_stmt_limitedContext) Column_name_list(i int) IColumn_name_listContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_name_listContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_name_listContext)\n}\n\nfunc (s *Update_stmt_limitedContext) With_clause() IWith_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWith_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWith_clauseContext)\n}\n\nfunc (s *Update_stmt_limitedContext) OR_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOR_, 0)\n}\n\nfunc (s *Update_stmt_limitedContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Update_stmt_limitedContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Update_stmt_limitedContext) WHERE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWHERE_, 0)\n}\n\nfunc (s *Update_stmt_limitedContext) Returning_clause() IReturning_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IReturning_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IReturning_clauseContext)\n}\n\nfunc (s *Update_stmt_limitedContext) Limit_stmt() ILimit_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ILimit_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ILimit_stmtContext)\n}\n\nfunc (s *Update_stmt_limitedContext) ROLLBACK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROLLBACK_, 0)\n}\n\nfunc (s *Update_stmt_limitedContext) ABORT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserABORT_, 0)\n}\n\nfunc (s *Update_stmt_limitedContext) REPLACE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREPLACE_, 0)\n}\n\nfunc (s *Update_stmt_limitedContext) FAIL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFAIL_, 0)\n}\n\nfunc (s *Update_stmt_limitedContext) IGNORE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIGNORE_, 0)\n}\n\nfunc (s *Update_stmt_limitedContext) Order_by_stmt() IOrder_by_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOrder_by_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOrder_by_stmtContext)\n}\n\nfunc (s *Update_stmt_limitedContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Update_stmt_limitedContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Update_stmt_limitedContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterUpdate_stmt_limited(s)\n\t}\n}\n\nfunc (s *Update_stmt_limitedContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitUpdate_stmt_limited(s)\n\t}\n}\n\nfunc (s *Update_stmt_limitedContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitUpdate_stmt_limited(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Update_stmt_limited() (localctx IUpdate_stmt_limitedContext) {\n\tlocalctx = NewUpdate_stmt_limitedContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 112, ParserRULE_update_stmt_limited)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(1596)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWITH_ {\n\t\t{\n\t\t\tp.SetState(1595)\n\t\t\tp.With_clause()\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(1598)\n\t\tp.Match(ParserUPDATE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1601)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 231, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(1599)\n\t\t\tp.Match(ParserOR_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1600)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserABORT_ || ((int64((_la-72)) & ^0x3f) == 0 && ((int64(1)<<(_la-72))&19140298416325121) != 0)) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1603)\n\t\tp.Qualified_table_name()\n\t}\n\t{\n\t\tp.SetState(1604)\n\t\tp.Match(ParserSET_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1607)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 232, p.GetParserRuleContext()) {\n\tcase 1:\n\t\t{\n\t\t\tp.SetState(1605)\n\t\t\tp.Column_name()\n\t\t}\n\n\tcase 2:\n\t\t{\n\t\t\tp.SetState(1606)\n\t\t\tp.Column_name_list()\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1609)\n\t\tp.Match(ParserASSIGN)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1610)\n\t\tp.expr(0)\n\t}\n\tp.SetState(1621)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA {\n\t\t{\n\t\t\tp.SetState(1611)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1614)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 233, p.GetParserRuleContext()) {\n\t\tcase 1:\n\t\t\t{\n\t\t\t\tp.SetState(1612)\n\t\t\t\tp.Column_name()\n\t\t\t}\n\n\t\tcase 2:\n\t\t\t{\n\t\t\t\tp.SetState(1613)\n\t\t\t\tp.Column_name_list()\n\t\t\t}\n\n\t\tcase antlr.ATNInvalidAltNumber:\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(1616)\n\t\t\tp.Match(ParserASSIGN)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1617)\n\t\t\tp.expr(0)\n\t\t}\n\n\t\tp.SetState(1623)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\tp.SetState(1626)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserWHERE_ {\n\t\t{\n\t\t\tp.SetState(1624)\n\t\t\tp.Match(ParserWHERE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1625)\n\t\t\tp.expr(0)\n\t\t}\n\n\t}\n\tp.SetState(1629)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserRETURNING_ {\n\t\t{\n\t\t\tp.SetState(1628)\n\t\t\tp.Returning_clause()\n\t\t}\n\n\t}\n\tp.SetState(1635)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserLIMIT_ || _la == ParserORDER_ {\n\t\tp.SetState(1632)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserORDER_ {\n\t\t\t{\n\t\t\t\tp.SetState(1631)\n\t\t\t\tp.Order_by_stmt()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1634)\n\t\t\tp.Limit_stmt()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IQualified_table_nameContext is an interface to support dynamic dispatch.\ntype IQualified_table_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tTable_name() ITable_nameContext\n\tSchema_name() ISchema_nameContext\n\tDOT() antlr.TerminalNode\n\tAS_() antlr.TerminalNode\n\tAlias() IAliasContext\n\tINDEXED_() antlr.TerminalNode\n\tBY_() antlr.TerminalNode\n\tIndex_name() IIndex_nameContext\n\tNOT_() antlr.TerminalNode\n\n\t// IsQualified_table_nameContext differentiates from other interfaces.\n\tIsQualified_table_nameContext()\n}\n\ntype Qualified_table_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyQualified_table_nameContext() *Qualified_table_nameContext {\n\tvar p = new(Qualified_table_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_qualified_table_name\n\treturn p\n}\n\nfunc InitEmptyQualified_table_nameContext(p *Qualified_table_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_qualified_table_name\n}\n\nfunc (*Qualified_table_nameContext) IsQualified_table_nameContext() {}\n\nfunc NewQualified_table_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Qualified_table_nameContext {\n\tvar p = new(Qualified_table_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_qualified_table_name\n\n\treturn p\n}\n\nfunc (s *Qualified_table_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Qualified_table_nameContext) Table_name() ITable_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ITable_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ITable_nameContext)\n}\n\nfunc (s *Qualified_table_nameContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Qualified_table_nameContext) DOT() antlr.TerminalNode {\n\treturn s.GetToken(ParserDOT, 0)\n}\n\nfunc (s *Qualified_table_nameContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *Qualified_table_nameContext) Alias() IAliasContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAliasContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAliasContext)\n}\n\nfunc (s *Qualified_table_nameContext) INDEXED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINDEXED_, 0)\n}\n\nfunc (s *Qualified_table_nameContext) BY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBY_, 0)\n}\n\nfunc (s *Qualified_table_nameContext) Index_name() IIndex_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IIndex_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IIndex_nameContext)\n}\n\nfunc (s *Qualified_table_nameContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *Qualified_table_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Qualified_table_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Qualified_table_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterQualified_table_name(s)\n\t}\n}\n\nfunc (s *Qualified_table_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitQualified_table_name(s)\n\t}\n}\n\nfunc (s *Qualified_table_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitQualified_table_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Qualified_table_name() (localctx IQualified_table_nameContext) {\n\tlocalctx = NewQualified_table_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 114, ParserRULE_qualified_table_name)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\tp.SetState(1640)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 239, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(1637)\n\t\t\tp.Schema_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1638)\n\t\t\tp.Match(ParserDOT)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1642)\n\t\tp.Table_name()\n\t}\n\tp.SetState(1645)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserAS_ {\n\t\t{\n\t\t\tp.SetState(1643)\n\t\t\tp.Match(ParserAS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1644)\n\t\t\tp.Alias()\n\t\t}\n\n\t}\n\tp.SetState(1652)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserINDEXED_:\n\t\t{\n\t\t\tp.SetState(1647)\n\t\t\tp.Match(ParserINDEXED_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1648)\n\t\t\tp.Match(ParserBY_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1649)\n\t\t\tp.Index_name()\n\t\t}\n\n\tcase ParserNOT_:\n\t\t{\n\t\t\tp.SetState(1650)\n\t\t\tp.Match(ParserNOT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1651)\n\t\t\tp.Match(ParserINDEXED_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 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_:\n\n\tdefault:\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IVacuum_stmtContext is an interface to support dynamic dispatch.\ntype IVacuum_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tVACUUM_() antlr.TerminalNode\n\tSchema_name() ISchema_nameContext\n\tINTO_() antlr.TerminalNode\n\tFilename() IFilenameContext\n\n\t// IsVacuum_stmtContext differentiates from other interfaces.\n\tIsVacuum_stmtContext()\n}\n\ntype Vacuum_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyVacuum_stmtContext() *Vacuum_stmtContext {\n\tvar p = new(Vacuum_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_vacuum_stmt\n\treturn p\n}\n\nfunc InitEmptyVacuum_stmtContext(p *Vacuum_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_vacuum_stmt\n}\n\nfunc (*Vacuum_stmtContext) IsVacuum_stmtContext() {}\n\nfunc NewVacuum_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Vacuum_stmtContext {\n\tvar p = new(Vacuum_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_vacuum_stmt\n\n\treturn p\n}\n\nfunc (s *Vacuum_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Vacuum_stmtContext) VACUUM_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVACUUM_, 0)\n}\n\nfunc (s *Vacuum_stmtContext) Schema_name() ISchema_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISchema_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISchema_nameContext)\n}\n\nfunc (s *Vacuum_stmtContext) INTO_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINTO_, 0)\n}\n\nfunc (s *Vacuum_stmtContext) Filename() IFilenameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFilenameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFilenameContext)\n}\n\nfunc (s *Vacuum_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Vacuum_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Vacuum_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterVacuum_stmt(s)\n\t}\n}\n\nfunc (s *Vacuum_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitVacuum_stmt(s)\n\t}\n}\n\nfunc (s *Vacuum_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitVacuum_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Vacuum_stmt() (localctx IVacuum_stmtContext) {\n\tlocalctx = NewVacuum_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 116, ParserRULE_vacuum_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1654)\n\t\tp.Match(ParserVACUUM_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1656)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 242, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(1655)\n\t\t\tp.Schema_name()\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\tp.SetState(1660)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserINTO_ {\n\t\t{\n\t\t\tp.SetState(1658)\n\t\t\tp.Match(ParserINTO_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1659)\n\t\t\tp.Filename()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IFilter_clauseContext is an interface to support dynamic dispatch.\ntype IFilter_clauseContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tFILTER_() antlr.TerminalNode\n\tOPEN_PAR() antlr.TerminalNode\n\tWHERE_() antlr.TerminalNode\n\tExpr() IExprContext\n\tCLOSE_PAR() antlr.TerminalNode\n\n\t// IsFilter_clauseContext differentiates from other interfaces.\n\tIsFilter_clauseContext()\n}\n\ntype Filter_clauseContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyFilter_clauseContext() *Filter_clauseContext {\n\tvar p = new(Filter_clauseContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_filter_clause\n\treturn p\n}\n\nfunc InitEmptyFilter_clauseContext(p *Filter_clauseContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_filter_clause\n}\n\nfunc (*Filter_clauseContext) IsFilter_clauseContext() {}\n\nfunc NewFilter_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Filter_clauseContext {\n\tvar p = new(Filter_clauseContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_filter_clause\n\n\treturn p\n}\n\nfunc (s *Filter_clauseContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Filter_clauseContext) FILTER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFILTER_, 0)\n}\n\nfunc (s *Filter_clauseContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Filter_clauseContext) WHERE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWHERE_, 0)\n}\n\nfunc (s *Filter_clauseContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Filter_clauseContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Filter_clauseContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Filter_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Filter_clauseContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterFilter_clause(s)\n\t}\n}\n\nfunc (s *Filter_clauseContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitFilter_clause(s)\n\t}\n}\n\nfunc (s *Filter_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitFilter_clause(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Filter_clause() (localctx IFilter_clauseContext) {\n\tlocalctx = NewFilter_clauseContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 118, ParserRULE_filter_clause)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1662)\n\t\tp.Match(ParserFILTER_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1663)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1664)\n\t\tp.Match(ParserWHERE_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1665)\n\t\tp.expr(0)\n\t}\n\t{\n\t\tp.SetState(1666)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IWindow_defnContext is an interface to support dynamic dispatch.\ntype IWindow_defnContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tOPEN_PAR() antlr.TerminalNode\n\tCLOSE_PAR() antlr.TerminalNode\n\tORDER_() antlr.TerminalNode\n\tAllBY_() []antlr.TerminalNode\n\tBY_(i int) antlr.TerminalNode\n\tAllOrdering_term() []IOrdering_termContext\n\tOrdering_term(i int) IOrdering_termContext\n\tBase_window_name() IBase_window_nameContext\n\tPARTITION_() antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tFrame_spec() IFrame_specContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsWindow_defnContext differentiates from other interfaces.\n\tIsWindow_defnContext()\n}\n\ntype Window_defnContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyWindow_defnContext() *Window_defnContext {\n\tvar p = new(Window_defnContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_window_defn\n\treturn p\n}\n\nfunc InitEmptyWindow_defnContext(p *Window_defnContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_window_defn\n}\n\nfunc (*Window_defnContext) IsWindow_defnContext() {}\n\nfunc NewWindow_defnContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Window_defnContext {\n\tvar p = new(Window_defnContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_window_defn\n\n\treturn p\n}\n\nfunc (s *Window_defnContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Window_defnContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Window_defnContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Window_defnContext) ORDER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserORDER_, 0)\n}\n\nfunc (s *Window_defnContext) AllBY_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserBY_)\n}\n\nfunc (s *Window_defnContext) BY_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserBY_, i)\n}\n\nfunc (s *Window_defnContext) AllOrdering_term() []IOrdering_termContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IOrdering_termContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IOrdering_termContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IOrdering_termContext); ok {\n\t\t\ttst[i] = t.(IOrdering_termContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Window_defnContext) Ordering_term(i int) IOrdering_termContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOrdering_termContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOrdering_termContext)\n}\n\nfunc (s *Window_defnContext) Base_window_name() IBase_window_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IBase_window_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IBase_window_nameContext)\n}\n\nfunc (s *Window_defnContext) PARTITION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPARTITION_, 0)\n}\n\nfunc (s *Window_defnContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Window_defnContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Window_defnContext) Frame_spec() IFrame_specContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFrame_specContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFrame_specContext)\n}\n\nfunc (s *Window_defnContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Window_defnContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Window_defnContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Window_defnContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Window_defnContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterWindow_defn(s)\n\t}\n}\n\nfunc (s *Window_defnContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitWindow_defn(s)\n\t}\n}\n\nfunc (s *Window_defnContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitWindow_defn(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Window_defn() (localctx IWindow_defnContext) {\n\tlocalctx = NewWindow_defnContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 120, ParserRULE_window_defn)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1668)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1670)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 244, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(1669)\n\t\t\tp.Base_window_name()\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\tp.SetState(1682)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserPARTITION_ {\n\t\t{\n\t\t\tp.SetState(1672)\n\t\t\tp.Match(ParserPARTITION_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1673)\n\t\t\tp.Match(ParserBY_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1674)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(1679)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1675)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1676)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t\tp.SetState(1681)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\n\t}\n\n\t{\n\t\tp.SetState(1684)\n\t\tp.Match(ParserORDER_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1685)\n\t\tp.Match(ParserBY_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1686)\n\t\tp.Ordering_term()\n\t}\n\tp.SetState(1691)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA {\n\t\t{\n\t\t\tp.SetState(1687)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1688)\n\t\t\tp.Ordering_term()\n\t\t}\n\n\t\tp.SetState(1693)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\n\tp.SetState(1695)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif (int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&2251799880794113) != 0 {\n\t\t{\n\t\t\tp.SetState(1694)\n\t\t\tp.Frame_spec()\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(1697)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IOver_clauseContext is an interface to support dynamic dispatch.\ntype IOver_clauseContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tOVER_() antlr.TerminalNode\n\tWindow_name() IWindow_nameContext\n\tOPEN_PAR() antlr.TerminalNode\n\tCLOSE_PAR() antlr.TerminalNode\n\tBase_window_name() IBase_window_nameContext\n\tPARTITION_() antlr.TerminalNode\n\tAllBY_() []antlr.TerminalNode\n\tBY_(i int) antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tORDER_() antlr.TerminalNode\n\tAllOrdering_term() []IOrdering_termContext\n\tOrdering_term(i int) IOrdering_termContext\n\tFrame_spec() IFrame_specContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsOver_clauseContext differentiates from other interfaces.\n\tIsOver_clauseContext()\n}\n\ntype Over_clauseContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyOver_clauseContext() *Over_clauseContext {\n\tvar p = new(Over_clauseContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_over_clause\n\treturn p\n}\n\nfunc InitEmptyOver_clauseContext(p *Over_clauseContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_over_clause\n}\n\nfunc (*Over_clauseContext) IsOver_clauseContext() {}\n\nfunc NewOver_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Over_clauseContext {\n\tvar p = new(Over_clauseContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_over_clause\n\n\treturn p\n}\n\nfunc (s *Over_clauseContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Over_clauseContext) OVER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOVER_, 0)\n}\n\nfunc (s *Over_clauseContext) Window_name() IWindow_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWindow_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWindow_nameContext)\n}\n\nfunc (s *Over_clauseContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Over_clauseContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Over_clauseContext) Base_window_name() IBase_window_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IBase_window_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IBase_window_nameContext)\n}\n\nfunc (s *Over_clauseContext) PARTITION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPARTITION_, 0)\n}\n\nfunc (s *Over_clauseContext) AllBY_() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserBY_)\n}\n\nfunc (s *Over_clauseContext) BY_(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserBY_, i)\n}\n\nfunc (s *Over_clauseContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Over_clauseContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Over_clauseContext) ORDER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserORDER_, 0)\n}\n\nfunc (s *Over_clauseContext) AllOrdering_term() []IOrdering_termContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IOrdering_termContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IOrdering_termContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IOrdering_termContext); ok {\n\t\t\ttst[i] = t.(IOrdering_termContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Over_clauseContext) Ordering_term(i int) IOrdering_termContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOrdering_termContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOrdering_termContext)\n}\n\nfunc (s *Over_clauseContext) Frame_spec() IFrame_specContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFrame_specContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFrame_specContext)\n}\n\nfunc (s *Over_clauseContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Over_clauseContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Over_clauseContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Over_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Over_clauseContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterOver_clause(s)\n\t}\n}\n\nfunc (s *Over_clauseContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitOver_clause(s)\n\t}\n}\n\nfunc (s *Over_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitOver_clause(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Over_clause() (localctx IOver_clauseContext) {\n\tlocalctx = NewOver_clauseContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 122, ParserRULE_over_clause)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1699)\n\t\tp.Match(ParserOVER_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1733)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 255, p.GetParserRuleContext()) {\n\tcase 1:\n\t\t{\n\t\t\tp.SetState(1700)\n\t\t\tp.Window_name()\n\t\t}\n\n\tcase 2:\n\t\t{\n\t\t\tp.SetState(1701)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1703)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 249, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(1702)\n\t\t\t\tp.Base_window_name()\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\tp.SetState(1715)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserPARTITION_ {\n\t\t\t{\n\t\t\t\tp.SetState(1705)\n\t\t\t\tp.Match(ParserPARTITION_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1706)\n\t\t\t\tp.Match(ParserBY_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1707)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\t\t\tp.SetState(1712)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1708)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1709)\n\t\t\t\t\tp.expr(0)\n\t\t\t\t}\n\n\t\t\t\tp.SetState(1714)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(1727)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserORDER_ {\n\t\t\t{\n\t\t\t\tp.SetState(1717)\n\t\t\t\tp.Match(ParserORDER_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1718)\n\t\t\t\tp.Match(ParserBY_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1719)\n\t\t\t\tp.Ordering_term()\n\t\t\t}\n\t\t\tp.SetState(1724)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tfor _la == ParserCOMMA {\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1720)\n\t\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\t\tif p.HasError() {\n\t\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\t\tgoto errorExit\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tp.SetState(1721)\n\t\t\t\t\tp.Ordering_term()\n\t\t\t\t}\n\n\t\t\t\tp.SetState(1726)\n\t\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(1730)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif (int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&2251799880794113) != 0 {\n\t\t\t{\n\t\t\t\tp.SetState(1729)\n\t\t\t\tp.Frame_spec()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1732)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IFrame_specContext is an interface to support dynamic dispatch.\ntype IFrame_specContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tFrame_clause() IFrame_clauseContext\n\tEXCLUDE_() antlr.TerminalNode\n\tCURRENT_() antlr.TerminalNode\n\tROW_() antlr.TerminalNode\n\tGROUP_() antlr.TerminalNode\n\tTIES_() antlr.TerminalNode\n\tNO_() antlr.TerminalNode\n\tOTHERS_() antlr.TerminalNode\n\n\t// IsFrame_specContext differentiates from other interfaces.\n\tIsFrame_specContext()\n}\n\ntype Frame_specContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyFrame_specContext() *Frame_specContext {\n\tvar p = new(Frame_specContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_frame_spec\n\treturn p\n}\n\nfunc InitEmptyFrame_specContext(p *Frame_specContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_frame_spec\n}\n\nfunc (*Frame_specContext) IsFrame_specContext() {}\n\nfunc NewFrame_specContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Frame_specContext {\n\tvar p = new(Frame_specContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_frame_spec\n\n\treturn p\n}\n\nfunc (s *Frame_specContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Frame_specContext) Frame_clause() IFrame_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFrame_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFrame_clauseContext)\n}\n\nfunc (s *Frame_specContext) EXCLUDE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXCLUDE_, 0)\n}\n\nfunc (s *Frame_specContext) CURRENT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_, 0)\n}\n\nfunc (s *Frame_specContext) ROW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROW_, 0)\n}\n\nfunc (s *Frame_specContext) GROUP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserGROUP_, 0)\n}\n\nfunc (s *Frame_specContext) TIES_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTIES_, 0)\n}\n\nfunc (s *Frame_specContext) NO_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNO_, 0)\n}\n\nfunc (s *Frame_specContext) OTHERS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOTHERS_, 0)\n}\n\nfunc (s *Frame_specContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Frame_specContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Frame_specContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterFrame_spec(s)\n\t}\n}\n\nfunc (s *Frame_specContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitFrame_spec(s)\n\t}\n}\n\nfunc (s *Frame_specContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitFrame_spec(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Frame_spec() (localctx IFrame_specContext) {\n\tlocalctx = NewFrame_specContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 124, ParserRULE_frame_spec)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1735)\n\t\tp.Frame_clause()\n\t}\n\tp.SetState(1743)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserEXCLUDE_:\n\t\t{\n\t\t\tp.SetState(1736)\n\t\t\tp.Match(ParserEXCLUDE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t\t{\n\t\t\tp.SetState(1737)\n\t\t\tp.Match(ParserNO_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1738)\n\t\t\tp.Match(ParserOTHERS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserCURRENT_:\n\t\t{\n\t\t\tp.SetState(1739)\n\t\t\tp.Match(ParserCURRENT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1740)\n\t\t\tp.Match(ParserROW_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserGROUP_:\n\t\t{\n\t\t\tp.SetState(1741)\n\t\t\tp.Match(ParserGROUP_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserTIES_:\n\t\t{\n\t\t\tp.SetState(1742)\n\t\t\tp.Match(ParserTIES_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserCLOSE_PAR:\n\n\tdefault:\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IFrame_clauseContext is an interface to support dynamic dispatch.\ntype IFrame_clauseContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tRANGE_() antlr.TerminalNode\n\tROWS_() antlr.TerminalNode\n\tGROUPS_() antlr.TerminalNode\n\tFrame_single() IFrame_singleContext\n\tBETWEEN_() antlr.TerminalNode\n\tFrame_left() IFrame_leftContext\n\tAND_() antlr.TerminalNode\n\tFrame_right() IFrame_rightContext\n\n\t// IsFrame_clauseContext differentiates from other interfaces.\n\tIsFrame_clauseContext()\n}\n\ntype Frame_clauseContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyFrame_clauseContext() *Frame_clauseContext {\n\tvar p = new(Frame_clauseContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_frame_clause\n\treturn p\n}\n\nfunc InitEmptyFrame_clauseContext(p *Frame_clauseContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_frame_clause\n}\n\nfunc (*Frame_clauseContext) IsFrame_clauseContext() {}\n\nfunc NewFrame_clauseContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Frame_clauseContext {\n\tvar p = new(Frame_clauseContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_frame_clause\n\n\treturn p\n}\n\nfunc (s *Frame_clauseContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Frame_clauseContext) RANGE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRANGE_, 0)\n}\n\nfunc (s *Frame_clauseContext) ROWS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROWS_, 0)\n}\n\nfunc (s *Frame_clauseContext) GROUPS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserGROUPS_, 0)\n}\n\nfunc (s *Frame_clauseContext) Frame_single() IFrame_singleContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFrame_singleContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFrame_singleContext)\n}\n\nfunc (s *Frame_clauseContext) BETWEEN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBETWEEN_, 0)\n}\n\nfunc (s *Frame_clauseContext) Frame_left() IFrame_leftContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFrame_leftContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFrame_leftContext)\n}\n\nfunc (s *Frame_clauseContext) AND_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAND_, 0)\n}\n\nfunc (s *Frame_clauseContext) Frame_right() IFrame_rightContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFrame_rightContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFrame_rightContext)\n}\n\nfunc (s *Frame_clauseContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Frame_clauseContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Frame_clauseContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterFrame_clause(s)\n\t}\n}\n\nfunc (s *Frame_clauseContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitFrame_clause(s)\n\t}\n}\n\nfunc (s *Frame_clauseContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitFrame_clause(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Frame_clause() (localctx IFrame_clauseContext) {\n\tlocalctx = NewFrame_clauseContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 126, ParserRULE_frame_clause)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1745)\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif !((int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&2251799880794113) != 0) {\n\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t} else {\n\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\tp.Consume()\n\t\t}\n\t}\n\tp.SetState(1752)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 257, p.GetParserRuleContext()) {\n\tcase 1:\n\t\t{\n\t\t\tp.SetState(1746)\n\t\t\tp.Frame_single()\n\t\t}\n\n\tcase 2:\n\t\t{\n\t\t\tp.SetState(1747)\n\t\t\tp.Match(ParserBETWEEN_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1748)\n\t\t\tp.Frame_left()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1749)\n\t\t\tp.Match(ParserAND_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1750)\n\t\t\tp.Frame_right()\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISimple_function_invocationContext is an interface to support dynamic dispatch.\ntype ISimple_function_invocationContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tSimple_func() ISimple_funcContext\n\tOPEN_PAR() antlr.TerminalNode\n\tCLOSE_PAR() antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tSTAR() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsSimple_function_invocationContext differentiates from other interfaces.\n\tIsSimple_function_invocationContext()\n}\n\ntype Simple_function_invocationContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySimple_function_invocationContext() *Simple_function_invocationContext {\n\tvar p = new(Simple_function_invocationContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_simple_function_invocation\n\treturn p\n}\n\nfunc InitEmptySimple_function_invocationContext(p *Simple_function_invocationContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_simple_function_invocation\n}\n\nfunc (*Simple_function_invocationContext) IsSimple_function_invocationContext() {}\n\nfunc NewSimple_function_invocationContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Simple_function_invocationContext {\n\tvar p = new(Simple_function_invocationContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_simple_function_invocation\n\n\treturn p\n}\n\nfunc (s *Simple_function_invocationContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Simple_function_invocationContext) Simple_func() ISimple_funcContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISimple_funcContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISimple_funcContext)\n}\n\nfunc (s *Simple_function_invocationContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Simple_function_invocationContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Simple_function_invocationContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Simple_function_invocationContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Simple_function_invocationContext) STAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTAR, 0)\n}\n\nfunc (s *Simple_function_invocationContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Simple_function_invocationContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Simple_function_invocationContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Simple_function_invocationContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Simple_function_invocationContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSimple_function_invocation(s)\n\t}\n}\n\nfunc (s *Simple_function_invocationContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSimple_function_invocation(s)\n\t}\n}\n\nfunc (s *Simple_function_invocationContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSimple_function_invocation(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Simple_function_invocation() (localctx ISimple_function_invocationContext) {\n\tlocalctx = NewSimple_function_invocationContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 128, ParserRULE_simple_function_invocation)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1754)\n\t\tp.Simple_func()\n\t}\n\t{\n\t\tp.SetState(1755)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1765)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase 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:\n\t\t{\n\t\t\tp.SetState(1756)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(1761)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1757)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1758)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t\tp.SetState(1763)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\n\tcase ParserSTAR:\n\t\t{\n\t\t\tp.SetState(1764)\n\t\t\tp.Match(ParserSTAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1767)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IAggregate_function_invocationContext is an interface to support dynamic dispatch.\ntype IAggregate_function_invocationContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAggregate_func() IAggregate_funcContext\n\tOPEN_PAR() antlr.TerminalNode\n\tCLOSE_PAR() antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tSTAR() antlr.TerminalNode\n\tFilter_clause() IFilter_clauseContext\n\tDISTINCT_() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsAggregate_function_invocationContext differentiates from other interfaces.\n\tIsAggregate_function_invocationContext()\n}\n\ntype Aggregate_function_invocationContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyAggregate_function_invocationContext() *Aggregate_function_invocationContext {\n\tvar p = new(Aggregate_function_invocationContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_aggregate_function_invocation\n\treturn p\n}\n\nfunc InitEmptyAggregate_function_invocationContext(p *Aggregate_function_invocationContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_aggregate_function_invocation\n}\n\nfunc (*Aggregate_function_invocationContext) IsAggregate_function_invocationContext() {}\n\nfunc NewAggregate_function_invocationContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Aggregate_function_invocationContext {\n\tvar p = new(Aggregate_function_invocationContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_aggregate_function_invocation\n\n\treturn p\n}\n\nfunc (s *Aggregate_function_invocationContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Aggregate_function_invocationContext) Aggregate_func() IAggregate_funcContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAggregate_funcContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAggregate_funcContext)\n}\n\nfunc (s *Aggregate_function_invocationContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Aggregate_function_invocationContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Aggregate_function_invocationContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Aggregate_function_invocationContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Aggregate_function_invocationContext) STAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTAR, 0)\n}\n\nfunc (s *Aggregate_function_invocationContext) Filter_clause() IFilter_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFilter_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFilter_clauseContext)\n}\n\nfunc (s *Aggregate_function_invocationContext) DISTINCT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDISTINCT_, 0)\n}\n\nfunc (s *Aggregate_function_invocationContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Aggregate_function_invocationContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Aggregate_function_invocationContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Aggregate_function_invocationContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Aggregate_function_invocationContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterAggregate_function_invocation(s)\n\t}\n}\n\nfunc (s *Aggregate_function_invocationContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitAggregate_function_invocation(s)\n\t}\n}\n\nfunc (s *Aggregate_function_invocationContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitAggregate_function_invocation(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Aggregate_function_invocation() (localctx IAggregate_function_invocationContext) {\n\tlocalctx = NewAggregate_function_invocationContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 130, ParserRULE_aggregate_function_invocation)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1769)\n\t\tp.Aggregate_func()\n\t}\n\t{\n\t\tp.SetState(1770)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1783)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\tswitch p.GetTokenStream().LA(1) {\n\tcase 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:\n\t\tp.SetState(1772)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 260, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(1771)\n\t\t\t\tp.Match(ParserDISTINCT_)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\t{\n\t\t\tp.SetState(1774)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(1779)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1775)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1776)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t\tp.SetState(1781)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\n\tcase ParserSTAR:\n\t\t{\n\t\t\tp.SetState(1782)\n\t\t\tp.Match(ParserSTAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserCLOSE_PAR:\n\n\tdefault:\n\t}\n\t{\n\t\tp.SetState(1785)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1787)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserFILTER_ {\n\t\t{\n\t\t\tp.SetState(1786)\n\t\t\tp.Filter_clause()\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IWindow_function_invocationContext is an interface to support dynamic dispatch.\ntype IWindow_function_invocationContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tWindow_function() IWindow_functionContext\n\tOPEN_PAR() antlr.TerminalNode\n\tCLOSE_PAR() antlr.TerminalNode\n\tOVER_() antlr.TerminalNode\n\tWindow_defn() IWindow_defnContext\n\tWindow_name() IWindow_nameContext\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tSTAR() antlr.TerminalNode\n\tFilter_clause() IFilter_clauseContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsWindow_function_invocationContext differentiates from other interfaces.\n\tIsWindow_function_invocationContext()\n}\n\ntype Window_function_invocationContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyWindow_function_invocationContext() *Window_function_invocationContext {\n\tvar p = new(Window_function_invocationContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_window_function_invocation\n\treturn p\n}\n\nfunc InitEmptyWindow_function_invocationContext(p *Window_function_invocationContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_window_function_invocation\n}\n\nfunc (*Window_function_invocationContext) IsWindow_function_invocationContext() {}\n\nfunc NewWindow_function_invocationContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Window_function_invocationContext {\n\tvar p = new(Window_function_invocationContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_window_function_invocation\n\n\treturn p\n}\n\nfunc (s *Window_function_invocationContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Window_function_invocationContext) Window_function() IWindow_functionContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWindow_functionContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWindow_functionContext)\n}\n\nfunc (s *Window_function_invocationContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Window_function_invocationContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Window_function_invocationContext) OVER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOVER_, 0)\n}\n\nfunc (s *Window_function_invocationContext) Window_defn() IWindow_defnContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWindow_defnContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWindow_defnContext)\n}\n\nfunc (s *Window_function_invocationContext) Window_name() IWindow_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IWindow_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IWindow_nameContext)\n}\n\nfunc (s *Window_function_invocationContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Window_function_invocationContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Window_function_invocationContext) STAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTAR, 0)\n}\n\nfunc (s *Window_function_invocationContext) Filter_clause() IFilter_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFilter_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFilter_clauseContext)\n}\n\nfunc (s *Window_function_invocationContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Window_function_invocationContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Window_function_invocationContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Window_function_invocationContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Window_function_invocationContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterWindow_function_invocation(s)\n\t}\n}\n\nfunc (s *Window_function_invocationContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitWindow_function_invocation(s)\n\t}\n}\n\nfunc (s *Window_function_invocationContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitWindow_function_invocation(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Window_function_invocation() (localctx IWindow_function_invocationContext) {\n\tlocalctx = NewWindow_function_invocationContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 132, ParserRULE_window_function_invocation)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1789)\n\t\tp.Window_function()\n\t}\n\t{\n\t\tp.SetState(1790)\n\t\tp.Match(ParserOPEN_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1800)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\tswitch p.GetTokenStream().LA(1) {\n\tcase 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:\n\t\t{\n\t\t\tp.SetState(1791)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(1796)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tfor _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1792)\n\t\t\t\tp.Match(ParserCOMMA)\n\t\t\t\tif p.HasError() {\n\t\t\t\t\t// Recognition error - abort rule\n\t\t\t\t\tgoto errorExit\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tp.SetState(1793)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\t\tp.SetState(1798)\n\t\t\tp.GetErrorHandler().Sync(p)\n\t\t\tif p.HasError() {\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t\t_la = p.GetTokenStream().LA(1)\n\t\t}\n\n\tcase ParserSTAR:\n\t\t{\n\t\t\tp.SetState(1799)\n\t\t\tp.Match(ParserSTAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserCLOSE_PAR:\n\n\tdefault:\n\t}\n\t{\n\t\tp.SetState(1802)\n\t\tp.Match(ParserCLOSE_PAR)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1804)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserFILTER_ {\n\t\t{\n\t\t\tp.SetState(1803)\n\t\t\tp.Filter_clause()\n\t\t}\n\n\t}\n\t{\n\t\tp.SetState(1806)\n\t\tp.Match(ParserOVER_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1809)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 267, p.GetParserRuleContext()) {\n\tcase 1:\n\t\t{\n\t\t\tp.SetState(1807)\n\t\t\tp.Window_defn()\n\t\t}\n\n\tcase 2:\n\t\t{\n\t\t\tp.SetState(1808)\n\t\t\tp.Window_name()\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICommon_table_stmtContext is an interface to support dynamic dispatch.\ntype ICommon_table_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tWITH_() antlr.TerminalNode\n\tAllCommon_table_expression() []ICommon_table_expressionContext\n\tCommon_table_expression(i int) ICommon_table_expressionContext\n\tRECURSIVE_() antlr.TerminalNode\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsCommon_table_stmtContext differentiates from other interfaces.\n\tIsCommon_table_stmtContext()\n}\n\ntype Common_table_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCommon_table_stmtContext() *Common_table_stmtContext {\n\tvar p = new(Common_table_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_common_table_stmt\n\treturn p\n}\n\nfunc InitEmptyCommon_table_stmtContext(p *Common_table_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_common_table_stmt\n}\n\nfunc (*Common_table_stmtContext) IsCommon_table_stmtContext() {}\n\nfunc NewCommon_table_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Common_table_stmtContext {\n\tvar p = new(Common_table_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_common_table_stmt\n\n\treturn p\n}\n\nfunc (s *Common_table_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Common_table_stmtContext) WITH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWITH_, 0)\n}\n\nfunc (s *Common_table_stmtContext) AllCommon_table_expression() []ICommon_table_expressionContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(ICommon_table_expressionContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]ICommon_table_expressionContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(ICommon_table_expressionContext); ok {\n\t\t\ttst[i] = t.(ICommon_table_expressionContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Common_table_stmtContext) Common_table_expression(i int) ICommon_table_expressionContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICommon_table_expressionContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICommon_table_expressionContext)\n}\n\nfunc (s *Common_table_stmtContext) RECURSIVE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRECURSIVE_, 0)\n}\n\nfunc (s *Common_table_stmtContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Common_table_stmtContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Common_table_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Common_table_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Common_table_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCommon_table_stmt(s)\n\t}\n}\n\nfunc (s *Common_table_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCommon_table_stmt(s)\n\t}\n}\n\nfunc (s *Common_table_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCommon_table_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Common_table_stmt() (localctx ICommon_table_stmtContext) {\n\tlocalctx = NewCommon_table_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 134, ParserRULE_common_table_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1811)\n\t\tp.Match(ParserWITH_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1813)\n\tp.GetErrorHandler().Sync(p)\n\n\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 268, p.GetParserRuleContext()) == 1 {\n\t\t{\n\t\t\tp.SetState(1812)\n\t\t\tp.Match(ParserRECURSIVE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\t} else if p.HasError() { // JIM\n\t\tgoto errorExit\n\t}\n\t{\n\t\tp.SetState(1815)\n\t\tp.Common_table_expression()\n\t}\n\tp.SetState(1820)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA {\n\t\t{\n\t\t\tp.SetState(1816)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1817)\n\t\t\tp.Common_table_expression()\n\t\t}\n\n\t\tp.SetState(1822)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IOrder_by_stmtContext is an interface to support dynamic dispatch.\ntype IOrder_by_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tORDER_() antlr.TerminalNode\n\tBY_() antlr.TerminalNode\n\tAllOrdering_term() []IOrdering_termContext\n\tOrdering_term(i int) IOrdering_termContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsOrder_by_stmtContext differentiates from other interfaces.\n\tIsOrder_by_stmtContext()\n}\n\ntype Order_by_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyOrder_by_stmtContext() *Order_by_stmtContext {\n\tvar p = new(Order_by_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_order_by_stmt\n\treturn p\n}\n\nfunc InitEmptyOrder_by_stmtContext(p *Order_by_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_order_by_stmt\n}\n\nfunc (*Order_by_stmtContext) IsOrder_by_stmtContext() {}\n\nfunc NewOrder_by_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Order_by_stmtContext {\n\tvar p = new(Order_by_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_order_by_stmt\n\n\treturn p\n}\n\nfunc (s *Order_by_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Order_by_stmtContext) ORDER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserORDER_, 0)\n}\n\nfunc (s *Order_by_stmtContext) BY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBY_, 0)\n}\n\nfunc (s *Order_by_stmtContext) AllOrdering_term() []IOrdering_termContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IOrdering_termContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IOrdering_termContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IOrdering_termContext); ok {\n\t\t\ttst[i] = t.(IOrdering_termContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Order_by_stmtContext) Ordering_term(i int) IOrdering_termContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOrdering_termContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOrdering_termContext)\n}\n\nfunc (s *Order_by_stmtContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Order_by_stmtContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Order_by_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Order_by_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Order_by_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterOrder_by_stmt(s)\n\t}\n}\n\nfunc (s *Order_by_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitOrder_by_stmt(s)\n\t}\n}\n\nfunc (s *Order_by_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitOrder_by_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Order_by_stmt() (localctx IOrder_by_stmtContext) {\n\tlocalctx = NewOrder_by_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 136, ParserRULE_order_by_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1823)\n\t\tp.Match(ParserORDER_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1824)\n\t\tp.Match(ParserBY_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1825)\n\t\tp.Ordering_term()\n\t}\n\tp.SetState(1830)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA {\n\t\t{\n\t\t\tp.SetState(1826)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1827)\n\t\t\tp.Ordering_term()\n\t\t}\n\n\t\tp.SetState(1832)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ILimit_stmtContext is an interface to support dynamic dispatch.\ntype ILimit_stmtContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tLIMIT_() antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tOFFSET_() antlr.TerminalNode\n\tCOMMA() antlr.TerminalNode\n\n\t// IsLimit_stmtContext differentiates from other interfaces.\n\tIsLimit_stmtContext()\n}\n\ntype Limit_stmtContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyLimit_stmtContext() *Limit_stmtContext {\n\tvar p = new(Limit_stmtContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_limit_stmt\n\treturn p\n}\n\nfunc InitEmptyLimit_stmtContext(p *Limit_stmtContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_limit_stmt\n}\n\nfunc (*Limit_stmtContext) IsLimit_stmtContext() {}\n\nfunc NewLimit_stmtContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Limit_stmtContext {\n\tvar p = new(Limit_stmtContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_limit_stmt\n\n\treturn p\n}\n\nfunc (s *Limit_stmtContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Limit_stmtContext) LIMIT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLIMIT_, 0)\n}\n\nfunc (s *Limit_stmtContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Limit_stmtContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Limit_stmtContext) OFFSET_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOFFSET_, 0)\n}\n\nfunc (s *Limit_stmtContext) COMMA() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, 0)\n}\n\nfunc (s *Limit_stmtContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Limit_stmtContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Limit_stmtContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterLimit_stmt(s)\n\t}\n}\n\nfunc (s *Limit_stmtContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitLimit_stmt(s)\n\t}\n}\n\nfunc (s *Limit_stmtContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitLimit_stmt(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Limit_stmt() (localctx ILimit_stmtContext) {\n\tlocalctx = NewLimit_stmtContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 138, ParserRULE_limit_stmt)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1833)\n\t\tp.Match(ParserLIMIT_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1834)\n\t\tp.expr(0)\n\t}\n\tp.SetState(1837)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserCOMMA || _la == ParserOFFSET_ {\n\t\t{\n\t\t\tp.SetState(1835)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserCOMMA || _la == ParserOFFSET_) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1836)\n\t\t\tp.expr(0)\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IOrdering_termContext is an interface to support dynamic dispatch.\ntype IOrdering_termContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tExpr() IExprContext\n\tCOLLATE_() antlr.TerminalNode\n\tCollation_name() ICollation_nameContext\n\tAsc_desc() IAsc_descContext\n\tNULLS_() antlr.TerminalNode\n\tFIRST_() antlr.TerminalNode\n\tLAST_() antlr.TerminalNode\n\n\t// IsOrdering_termContext differentiates from other interfaces.\n\tIsOrdering_termContext()\n}\n\ntype Ordering_termContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyOrdering_termContext() *Ordering_termContext {\n\tvar p = new(Ordering_termContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_ordering_term\n\treturn p\n}\n\nfunc InitEmptyOrdering_termContext(p *Ordering_termContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_ordering_term\n}\n\nfunc (*Ordering_termContext) IsOrdering_termContext() {}\n\nfunc NewOrdering_termContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Ordering_termContext {\n\tvar p = new(Ordering_termContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_ordering_term\n\n\treturn p\n}\n\nfunc (s *Ordering_termContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Ordering_termContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Ordering_termContext) COLLATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOLLATE_, 0)\n}\n\nfunc (s *Ordering_termContext) Collation_name() ICollation_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ICollation_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ICollation_nameContext)\n}\n\nfunc (s *Ordering_termContext) Asc_desc() IAsc_descContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAsc_descContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAsc_descContext)\n}\n\nfunc (s *Ordering_termContext) NULLS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNULLS_, 0)\n}\n\nfunc (s *Ordering_termContext) FIRST_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFIRST_, 0)\n}\n\nfunc (s *Ordering_termContext) LAST_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLAST_, 0)\n}\n\nfunc (s *Ordering_termContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Ordering_termContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Ordering_termContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterOrdering_term(s)\n\t}\n}\n\nfunc (s *Ordering_termContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitOrdering_term(s)\n\t}\n}\n\nfunc (s *Ordering_termContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitOrdering_term(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Ordering_term() (localctx IOrdering_termContext) {\n\tlocalctx = NewOrdering_termContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 140, ParserRULE_ordering_term)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1839)\n\t\tp.expr(0)\n\t}\n\tp.SetState(1842)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserCOLLATE_ {\n\t\t{\n\t\t\tp.SetState(1840)\n\t\t\tp.Match(ParserCOLLATE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1841)\n\t\t\tp.Collation_name()\n\t\t}\n\n\t}\n\tp.SetState(1845)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserASC_ || _la == ParserDESC_ {\n\t\t{\n\t\t\tp.SetState(1844)\n\t\t\tp.Asc_desc()\n\t\t}\n\n\t}\n\tp.SetState(1849)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserNULLS_ {\n\t\t{\n\t\t\tp.SetState(1847)\n\t\t\tp.Match(ParserNULLS_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1848)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserFIRST_ || _la == ParserLAST_) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IAsc_descContext is an interface to support dynamic dispatch.\ntype IAsc_descContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tASC_() antlr.TerminalNode\n\tDESC_() antlr.TerminalNode\n\n\t// IsAsc_descContext differentiates from other interfaces.\n\tIsAsc_descContext()\n}\n\ntype Asc_descContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyAsc_descContext() *Asc_descContext {\n\tvar p = new(Asc_descContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_asc_desc\n\treturn p\n}\n\nfunc InitEmptyAsc_descContext(p *Asc_descContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_asc_desc\n}\n\nfunc (*Asc_descContext) IsAsc_descContext() {}\n\nfunc NewAsc_descContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Asc_descContext {\n\tvar p = new(Asc_descContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_asc_desc\n\n\treturn p\n}\n\nfunc (s *Asc_descContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Asc_descContext) ASC_() antlr.TerminalNode {\n\treturn s.GetToken(ParserASC_, 0)\n}\n\nfunc (s *Asc_descContext) DESC_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDESC_, 0)\n}\n\nfunc (s *Asc_descContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Asc_descContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Asc_descContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterAsc_desc(s)\n\t}\n}\n\nfunc (s *Asc_descContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitAsc_desc(s)\n\t}\n}\n\nfunc (s *Asc_descContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitAsc_desc(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Asc_desc() (localctx IAsc_descContext) {\n\tlocalctx = NewAsc_descContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 142, ParserRULE_asc_desc)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1851)\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif !(_la == ParserASC_ || _la == ParserDESC_) {\n\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t} else {\n\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\tp.Consume()\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IFrame_leftContext is an interface to support dynamic dispatch.\ntype IFrame_leftContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tExpr() IExprContext\n\tPRECEDING_() antlr.TerminalNode\n\tFOLLOWING_() antlr.TerminalNode\n\tCURRENT_() antlr.TerminalNode\n\tROW_() antlr.TerminalNode\n\tUNBOUNDED_() antlr.TerminalNode\n\n\t// IsFrame_leftContext differentiates from other interfaces.\n\tIsFrame_leftContext()\n}\n\ntype Frame_leftContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyFrame_leftContext() *Frame_leftContext {\n\tvar p = new(Frame_leftContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_frame_left\n\treturn p\n}\n\nfunc InitEmptyFrame_leftContext(p *Frame_leftContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_frame_left\n}\n\nfunc (*Frame_leftContext) IsFrame_leftContext() {}\n\nfunc NewFrame_leftContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Frame_leftContext {\n\tvar p = new(Frame_leftContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_frame_left\n\n\treturn p\n}\n\nfunc (s *Frame_leftContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Frame_leftContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Frame_leftContext) PRECEDING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPRECEDING_, 0)\n}\n\nfunc (s *Frame_leftContext) FOLLOWING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFOLLOWING_, 0)\n}\n\nfunc (s *Frame_leftContext) CURRENT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_, 0)\n}\n\nfunc (s *Frame_leftContext) ROW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROW_, 0)\n}\n\nfunc (s *Frame_leftContext) UNBOUNDED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNBOUNDED_, 0)\n}\n\nfunc (s *Frame_leftContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Frame_leftContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Frame_leftContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterFrame_left(s)\n\t}\n}\n\nfunc (s *Frame_leftContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitFrame_left(s)\n\t}\n}\n\nfunc (s *Frame_leftContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitFrame_left(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Frame_left() (localctx IFrame_leftContext) {\n\tlocalctx = NewFrame_leftContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 144, ParserRULE_frame_left)\n\tp.SetState(1863)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 275, p.GetParserRuleContext()) {\n\tcase 1:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(1853)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1854)\n\t\t\tp.Match(ParserPRECEDING_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 2:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(1856)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1857)\n\t\t\tp.Match(ParserFOLLOWING_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 3:\n\t\tp.EnterOuterAlt(localctx, 3)\n\t\t{\n\t\t\tp.SetState(1859)\n\t\t\tp.Match(ParserCURRENT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1860)\n\t\t\tp.Match(ParserROW_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 4:\n\t\tp.EnterOuterAlt(localctx, 4)\n\t\t{\n\t\t\tp.SetState(1861)\n\t\t\tp.Match(ParserUNBOUNDED_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1862)\n\t\t\tp.Match(ParserPRECEDING_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IFrame_rightContext is an interface to support dynamic dispatch.\ntype IFrame_rightContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tExpr() IExprContext\n\tPRECEDING_() antlr.TerminalNode\n\tFOLLOWING_() antlr.TerminalNode\n\tCURRENT_() antlr.TerminalNode\n\tROW_() antlr.TerminalNode\n\tUNBOUNDED_() antlr.TerminalNode\n\n\t// IsFrame_rightContext differentiates from other interfaces.\n\tIsFrame_rightContext()\n}\n\ntype Frame_rightContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyFrame_rightContext() *Frame_rightContext {\n\tvar p = new(Frame_rightContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_frame_right\n\treturn p\n}\n\nfunc InitEmptyFrame_rightContext(p *Frame_rightContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_frame_right\n}\n\nfunc (*Frame_rightContext) IsFrame_rightContext() {}\n\nfunc NewFrame_rightContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Frame_rightContext {\n\tvar p = new(Frame_rightContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_frame_right\n\n\treturn p\n}\n\nfunc (s *Frame_rightContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Frame_rightContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Frame_rightContext) PRECEDING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPRECEDING_, 0)\n}\n\nfunc (s *Frame_rightContext) FOLLOWING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFOLLOWING_, 0)\n}\n\nfunc (s *Frame_rightContext) CURRENT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_, 0)\n}\n\nfunc (s *Frame_rightContext) ROW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROW_, 0)\n}\n\nfunc (s *Frame_rightContext) UNBOUNDED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNBOUNDED_, 0)\n}\n\nfunc (s *Frame_rightContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Frame_rightContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Frame_rightContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterFrame_right(s)\n\t}\n}\n\nfunc (s *Frame_rightContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitFrame_right(s)\n\t}\n}\n\nfunc (s *Frame_rightContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitFrame_right(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Frame_right() (localctx IFrame_rightContext) {\n\tlocalctx = NewFrame_rightContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 146, ParserRULE_frame_right)\n\tp.SetState(1875)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 276, p.GetParserRuleContext()) {\n\tcase 1:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(1865)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1866)\n\t\t\tp.Match(ParserPRECEDING_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 2:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(1868)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1869)\n\t\t\tp.Match(ParserFOLLOWING_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 3:\n\t\tp.EnterOuterAlt(localctx, 3)\n\t\t{\n\t\t\tp.SetState(1871)\n\t\t\tp.Match(ParserCURRENT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1872)\n\t\t\tp.Match(ParserROW_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 4:\n\t\tp.EnterOuterAlt(localctx, 4)\n\t\t{\n\t\t\tp.SetState(1873)\n\t\t\tp.Match(ParserUNBOUNDED_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1874)\n\t\t\tp.Match(ParserFOLLOWING_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IFrame_singleContext is an interface to support dynamic dispatch.\ntype IFrame_singleContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tExpr() IExprContext\n\tPRECEDING_() antlr.TerminalNode\n\tUNBOUNDED_() antlr.TerminalNode\n\tCURRENT_() antlr.TerminalNode\n\tROW_() antlr.TerminalNode\n\n\t// IsFrame_singleContext differentiates from other interfaces.\n\tIsFrame_singleContext()\n}\n\ntype Frame_singleContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyFrame_singleContext() *Frame_singleContext {\n\tvar p = new(Frame_singleContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_frame_single\n\treturn p\n}\n\nfunc InitEmptyFrame_singleContext(p *Frame_singleContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_frame_single\n}\n\nfunc (*Frame_singleContext) IsFrame_singleContext() {}\n\nfunc NewFrame_singleContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Frame_singleContext {\n\tvar p = new(Frame_singleContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_frame_single\n\n\treturn p\n}\n\nfunc (s *Frame_singleContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Frame_singleContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Frame_singleContext) PRECEDING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPRECEDING_, 0)\n}\n\nfunc (s *Frame_singleContext) UNBOUNDED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNBOUNDED_, 0)\n}\n\nfunc (s *Frame_singleContext) CURRENT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_, 0)\n}\n\nfunc (s *Frame_singleContext) ROW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROW_, 0)\n}\n\nfunc (s *Frame_singleContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Frame_singleContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Frame_singleContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterFrame_single(s)\n\t}\n}\n\nfunc (s *Frame_singleContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitFrame_single(s)\n\t}\n}\n\nfunc (s *Frame_singleContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitFrame_single(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Frame_single() (localctx IFrame_singleContext) {\n\tlocalctx = NewFrame_singleContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 148, ParserRULE_frame_single)\n\tp.SetState(1884)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 277, p.GetParserRuleContext()) {\n\tcase 1:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(1877)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1878)\n\t\t\tp.Match(ParserPRECEDING_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 2:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(1880)\n\t\t\tp.Match(ParserUNBOUNDED_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1881)\n\t\t\tp.Match(ParserPRECEDING_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 3:\n\t\tp.EnterOuterAlt(localctx, 3)\n\t\t{\n\t\t\tp.SetState(1882)\n\t\t\tp.Match(ParserCURRENT_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1883)\n\t\t\tp.Match(ParserROW_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IWindow_functionContext is an interface to support dynamic dispatch.\ntype IWindow_functionContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAllOPEN_PAR() []antlr.TerminalNode\n\tOPEN_PAR(i int) antlr.TerminalNode\n\tExpr() IExprContext\n\tAllCLOSE_PAR() []antlr.TerminalNode\n\tCLOSE_PAR(i int) antlr.TerminalNode\n\tOVER_() antlr.TerminalNode\n\tOrder_by_expr_asc_desc() IOrder_by_expr_asc_descContext\n\tFIRST_VALUE_() antlr.TerminalNode\n\tLAST_VALUE_() antlr.TerminalNode\n\tPartition_by() IPartition_byContext\n\tFrame_clause() IFrame_clauseContext\n\tCUME_DIST_() antlr.TerminalNode\n\tPERCENT_RANK_() antlr.TerminalNode\n\tOrder_by_expr() IOrder_by_exprContext\n\tDENSE_RANK_() antlr.TerminalNode\n\tRANK_() antlr.TerminalNode\n\tROW_NUMBER_() antlr.TerminalNode\n\tLAG_() antlr.TerminalNode\n\tLEAD_() antlr.TerminalNode\n\tOffset() IOffsetContext\n\tDefault_value() IDefault_valueContext\n\tNTH_VALUE_() antlr.TerminalNode\n\tCOMMA() antlr.TerminalNode\n\tSigned_number() ISigned_numberContext\n\tNTILE_() antlr.TerminalNode\n\n\t// IsWindow_functionContext differentiates from other interfaces.\n\tIsWindow_functionContext()\n}\n\ntype Window_functionContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyWindow_functionContext() *Window_functionContext {\n\tvar p = new(Window_functionContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_window_function\n\treturn p\n}\n\nfunc InitEmptyWindow_functionContext(p *Window_functionContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_window_function\n}\n\nfunc (*Window_functionContext) IsWindow_functionContext() {}\n\nfunc NewWindow_functionContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Window_functionContext {\n\tvar p = new(Window_functionContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_window_function\n\n\treturn p\n}\n\nfunc (s *Window_functionContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Window_functionContext) AllOPEN_PAR() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserOPEN_PAR)\n}\n\nfunc (s *Window_functionContext) OPEN_PAR(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, i)\n}\n\nfunc (s *Window_functionContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Window_functionContext) AllCLOSE_PAR() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCLOSE_PAR)\n}\n\nfunc (s *Window_functionContext) CLOSE_PAR(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, i)\n}\n\nfunc (s *Window_functionContext) OVER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOVER_, 0)\n}\n\nfunc (s *Window_functionContext) Order_by_expr_asc_desc() IOrder_by_expr_asc_descContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOrder_by_expr_asc_descContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOrder_by_expr_asc_descContext)\n}\n\nfunc (s *Window_functionContext) FIRST_VALUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFIRST_VALUE_, 0)\n}\n\nfunc (s *Window_functionContext) LAST_VALUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLAST_VALUE_, 0)\n}\n\nfunc (s *Window_functionContext) Partition_by() IPartition_byContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IPartition_byContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IPartition_byContext)\n}\n\nfunc (s *Window_functionContext) Frame_clause() IFrame_clauseContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IFrame_clauseContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IFrame_clauseContext)\n}\n\nfunc (s *Window_functionContext) CUME_DIST_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCUME_DIST_, 0)\n}\n\nfunc (s *Window_functionContext) PERCENT_RANK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPERCENT_RANK_, 0)\n}\n\nfunc (s *Window_functionContext) Order_by_expr() IOrder_by_exprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOrder_by_exprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOrder_by_exprContext)\n}\n\nfunc (s *Window_functionContext) DENSE_RANK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDENSE_RANK_, 0)\n}\n\nfunc (s *Window_functionContext) RANK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRANK_, 0)\n}\n\nfunc (s *Window_functionContext) ROW_NUMBER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROW_NUMBER_, 0)\n}\n\nfunc (s *Window_functionContext) LAG_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLAG_, 0)\n}\n\nfunc (s *Window_functionContext) LEAD_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLEAD_, 0)\n}\n\nfunc (s *Window_functionContext) Offset() IOffsetContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IOffsetContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IOffsetContext)\n}\n\nfunc (s *Window_functionContext) Default_value() IDefault_valueContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IDefault_valueContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IDefault_valueContext)\n}\n\nfunc (s *Window_functionContext) NTH_VALUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNTH_VALUE_, 0)\n}\n\nfunc (s *Window_functionContext) COMMA() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, 0)\n}\n\nfunc (s *Window_functionContext) Signed_number() ISigned_numberContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISigned_numberContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISigned_numberContext)\n}\n\nfunc (s *Window_functionContext) NTILE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNTILE_, 0)\n}\n\nfunc (s *Window_functionContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Window_functionContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Window_functionContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterWindow_function(s)\n\t}\n}\n\nfunc (s *Window_functionContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitWindow_function(s)\n\t}\n}\n\nfunc (s *Window_functionContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitWindow_function(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Window_function() (localctx IWindow_functionContext) {\n\tlocalctx = NewWindow_functionContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 150, ParserRULE_window_function)\n\tvar _la int\n\n\tp.SetState(1971)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserFIRST_VALUE_, ParserLAST_VALUE_:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(1886)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserFIRST_VALUE_ || _la == ParserLAST_VALUE_) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1887)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1888)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1889)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1890)\n\t\t\tp.Match(ParserOVER_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1891)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1893)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserPARTITION_ {\n\t\t\t{\n\t\t\t\tp.SetState(1892)\n\t\t\t\tp.Partition_by()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1895)\n\t\t\tp.Order_by_expr_asc_desc()\n\t\t}\n\t\tp.SetState(1897)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif (int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&2251799880794113) != 0 {\n\t\t\t{\n\t\t\t\tp.SetState(1896)\n\t\t\t\tp.Frame_clause()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1899)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserCUME_DIST_, ParserPERCENT_RANK_:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(1901)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserCUME_DIST_ || _la == ParserPERCENT_RANK_) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1902)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1903)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1904)\n\t\t\tp.Match(ParserOVER_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1905)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1907)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserPARTITION_ {\n\t\t\t{\n\t\t\t\tp.SetState(1906)\n\t\t\t\tp.Partition_by()\n\t\t\t}\n\n\t\t}\n\t\tp.SetState(1910)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserORDER_ {\n\t\t\t{\n\t\t\t\tp.SetState(1909)\n\t\t\t\tp.Order_by_expr()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1912)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserDENSE_RANK_, ParserRANK_, ParserROW_NUMBER_:\n\t\tp.EnterOuterAlt(localctx, 3)\n\t\t{\n\t\t\tp.SetState(1913)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !((int64((_la-160)) & ^0x3f) == 0 && ((int64(1)<<(_la-160))&385) != 0) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1914)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1915)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1916)\n\t\t\tp.Match(ParserOVER_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1917)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1919)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserPARTITION_ {\n\t\t\t{\n\t\t\t\tp.SetState(1918)\n\t\t\t\tp.Partition_by()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1921)\n\t\t\tp.Order_by_expr_asc_desc()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1922)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserLAG_, ParserLEAD_:\n\t\tp.EnterOuterAlt(localctx, 4)\n\t\t{\n\t\t\tp.SetState(1924)\n\t\t\t_la = p.GetTokenStream().LA(1)\n\n\t\t\tif !(_la == ParserLAG_ || _la == ParserLEAD_) {\n\t\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t\t} else {\n\t\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\t\tp.Consume()\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1925)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1926)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(1928)\n\t\tp.GetErrorHandler().Sync(p)\n\n\t\tif p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 283, p.GetParserRuleContext()) == 1 {\n\t\t\t{\n\t\t\t\tp.SetState(1927)\n\t\t\t\tp.Offset()\n\t\t\t}\n\n\t\t} else if p.HasError() { // JIM\n\t\t\tgoto errorExit\n\t\t}\n\t\tp.SetState(1931)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserCOMMA {\n\t\t\t{\n\t\t\t\tp.SetState(1930)\n\t\t\t\tp.Default_value()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1933)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1934)\n\t\t\tp.Match(ParserOVER_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1935)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1937)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserPARTITION_ {\n\t\t\t{\n\t\t\t\tp.SetState(1936)\n\t\t\t\tp.Partition_by()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1939)\n\t\t\tp.Order_by_expr_asc_desc()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1940)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserNTH_VALUE_:\n\t\tp.EnterOuterAlt(localctx, 5)\n\t\t{\n\t\t\tp.SetState(1942)\n\t\t\tp.Match(ParserNTH_VALUE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1943)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1944)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1945)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1946)\n\t\t\tp.Signed_number()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1947)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1948)\n\t\t\tp.Match(ParserOVER_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1949)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1951)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserPARTITION_ {\n\t\t\t{\n\t\t\t\tp.SetState(1950)\n\t\t\t\tp.Partition_by()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1953)\n\t\t\tp.Order_by_expr_asc_desc()\n\t\t}\n\t\tp.SetState(1955)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif (int64((_la-128)) & ^0x3f) == 0 && ((int64(1)<<(_la-128))&2251799880794113) != 0 {\n\t\t\t{\n\t\t\t\tp.SetState(1954)\n\t\t\t\tp.Frame_clause()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1957)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserNTILE_:\n\t\tp.EnterOuterAlt(localctx, 6)\n\t\t{\n\t\t\tp.SetState(1959)\n\t\t\tp.Match(ParserNTILE_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1960)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1961)\n\t\t\tp.expr(0)\n\t\t}\n\t\t{\n\t\t\tp.SetState(1962)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1963)\n\t\t\tp.Match(ParserOVER_)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(1964)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\tp.SetState(1966)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserPARTITION_ {\n\t\t\t{\n\t\t\t\tp.SetState(1965)\n\t\t\t\tp.Partition_by()\n\t\t\t}\n\n\t\t}\n\t\t{\n\t\t\tp.SetState(1968)\n\t\t\tp.Order_by_expr_asc_desc()\n\t\t}\n\t\t{\n\t\t\tp.SetState(1969)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IOffsetContext is an interface to support dynamic dispatch.\ntype IOffsetContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tCOMMA() antlr.TerminalNode\n\tSigned_number() ISigned_numberContext\n\n\t// IsOffsetContext differentiates from other interfaces.\n\tIsOffsetContext()\n}\n\ntype OffsetContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyOffsetContext() *OffsetContext {\n\tvar p = new(OffsetContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_offset\n\treturn p\n}\n\nfunc InitEmptyOffsetContext(p *OffsetContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_offset\n}\n\nfunc (*OffsetContext) IsOffsetContext() {}\n\nfunc NewOffsetContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *OffsetContext {\n\tvar p = new(OffsetContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_offset\n\n\treturn p\n}\n\nfunc (s *OffsetContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *OffsetContext) COMMA() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, 0)\n}\n\nfunc (s *OffsetContext) Signed_number() ISigned_numberContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISigned_numberContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISigned_numberContext)\n}\n\nfunc (s *OffsetContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *OffsetContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *OffsetContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterOffset(s)\n\t}\n}\n\nfunc (s *OffsetContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitOffset(s)\n\t}\n}\n\nfunc (s *OffsetContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitOffset(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Offset() (localctx IOffsetContext) {\n\tlocalctx = NewOffsetContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 152, ParserRULE_offset)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1973)\n\t\tp.Match(ParserCOMMA)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1974)\n\t\tp.Signed_number()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IDefault_valueContext is an interface to support dynamic dispatch.\ntype IDefault_valueContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tCOMMA() antlr.TerminalNode\n\tSigned_number() ISigned_numberContext\n\n\t// IsDefault_valueContext differentiates from other interfaces.\n\tIsDefault_valueContext()\n}\n\ntype Default_valueContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyDefault_valueContext() *Default_valueContext {\n\tvar p = new(Default_valueContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_default_value\n\treturn p\n}\n\nfunc InitEmptyDefault_valueContext(p *Default_valueContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_default_value\n}\n\nfunc (*Default_valueContext) IsDefault_valueContext() {}\n\nfunc NewDefault_valueContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Default_valueContext {\n\tvar p = new(Default_valueContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_default_value\n\n\treturn p\n}\n\nfunc (s *Default_valueContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Default_valueContext) COMMA() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, 0)\n}\n\nfunc (s *Default_valueContext) Signed_number() ISigned_numberContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISigned_numberContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISigned_numberContext)\n}\n\nfunc (s *Default_valueContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Default_valueContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Default_valueContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterDefault_value(s)\n\t}\n}\n\nfunc (s *Default_valueContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitDefault_value(s)\n\t}\n}\n\nfunc (s *Default_valueContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitDefault_value(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Default_value() (localctx IDefault_valueContext) {\n\tlocalctx = NewDefault_valueContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 154, ParserRULE_default_value)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1976)\n\t\tp.Match(ParserCOMMA)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1977)\n\t\tp.Signed_number()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IPartition_byContext is an interface to support dynamic dispatch.\ntype IPartition_byContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tPARTITION_() antlr.TerminalNode\n\tBY_() antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\n\t// IsPartition_byContext differentiates from other interfaces.\n\tIsPartition_byContext()\n}\n\ntype Partition_byContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyPartition_byContext() *Partition_byContext {\n\tvar p = new(Partition_byContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_partition_by\n\treturn p\n}\n\nfunc InitEmptyPartition_byContext(p *Partition_byContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_partition_by\n}\n\nfunc (*Partition_byContext) IsPartition_byContext() {}\n\nfunc NewPartition_byContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Partition_byContext {\n\tvar p = new(Partition_byContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_partition_by\n\n\treturn p\n}\n\nfunc (s *Partition_byContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Partition_byContext) PARTITION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPARTITION_, 0)\n}\n\nfunc (s *Partition_byContext) BY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBY_, 0)\n}\n\nfunc (s *Partition_byContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Partition_byContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Partition_byContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Partition_byContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Partition_byContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterPartition_by(s)\n\t}\n}\n\nfunc (s *Partition_byContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitPartition_by(s)\n\t}\n}\n\nfunc (s *Partition_byContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitPartition_by(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Partition_by() (localctx IPartition_byContext) {\n\tlocalctx = NewPartition_byContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 156, ParserRULE_partition_by)\n\tvar _alt int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1979)\n\t\tp.Match(ParserPARTITION_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1980)\n\t\tp.Match(ParserBY_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1982)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_alt = 1\n\tfor ok := true; ok; ok = _alt != 2 && _alt != antlr.ATNInvalidAltNumber {\n\t\tswitch _alt {\n\t\tcase 1:\n\t\t\t{\n\t\t\t\tp.SetState(1981)\n\t\t\t\tp.expr(0)\n\t\t\t}\n\n\t\tdefault:\n\t\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\t\tgoto errorExit\n\t\t}\n\n\t\tp.SetState(1984)\n\t\tp.GetErrorHandler().Sync(p)\n\t\t_alt = p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 290, p.GetParserRuleContext())\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IOrder_by_exprContext is an interface to support dynamic dispatch.\ntype IOrder_by_exprContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tORDER_() antlr.TerminalNode\n\tBY_() antlr.TerminalNode\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\n\t// IsOrder_by_exprContext differentiates from other interfaces.\n\tIsOrder_by_exprContext()\n}\n\ntype Order_by_exprContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyOrder_by_exprContext() *Order_by_exprContext {\n\tvar p = new(Order_by_exprContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_order_by_expr\n\treturn p\n}\n\nfunc InitEmptyOrder_by_exprContext(p *Order_by_exprContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_order_by_expr\n}\n\nfunc (*Order_by_exprContext) IsOrder_by_exprContext() {}\n\nfunc NewOrder_by_exprContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Order_by_exprContext {\n\tvar p = new(Order_by_exprContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_order_by_expr\n\n\treturn p\n}\n\nfunc (s *Order_by_exprContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Order_by_exprContext) ORDER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserORDER_, 0)\n}\n\nfunc (s *Order_by_exprContext) BY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBY_, 0)\n}\n\nfunc (s *Order_by_exprContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Order_by_exprContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Order_by_exprContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Order_by_exprContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Order_by_exprContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterOrder_by_expr(s)\n\t}\n}\n\nfunc (s *Order_by_exprContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitOrder_by_expr(s)\n\t}\n}\n\nfunc (s *Order_by_exprContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitOrder_by_expr(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Order_by_expr() (localctx IOrder_by_exprContext) {\n\tlocalctx = NewOrder_by_exprContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 158, ParserRULE_order_by_expr)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1986)\n\t\tp.Match(ParserORDER_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1987)\n\t\tp.Match(ParserBY_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\tp.SetState(1989)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor 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) {\n\t\t{\n\t\t\tp.SetState(1988)\n\t\t\tp.expr(0)\n\t\t}\n\n\t\tp.SetState(1991)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IOrder_by_expr_asc_descContext is an interface to support dynamic dispatch.\ntype IOrder_by_expr_asc_descContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tORDER_() antlr.TerminalNode\n\tBY_() antlr.TerminalNode\n\tExpr_asc_desc() IExpr_asc_descContext\n\n\t// IsOrder_by_expr_asc_descContext differentiates from other interfaces.\n\tIsOrder_by_expr_asc_descContext()\n}\n\ntype Order_by_expr_asc_descContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyOrder_by_expr_asc_descContext() *Order_by_expr_asc_descContext {\n\tvar p = new(Order_by_expr_asc_descContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_order_by_expr_asc_desc\n\treturn p\n}\n\nfunc InitEmptyOrder_by_expr_asc_descContext(p *Order_by_expr_asc_descContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_order_by_expr_asc_desc\n}\n\nfunc (*Order_by_expr_asc_descContext) IsOrder_by_expr_asc_descContext() {}\n\nfunc NewOrder_by_expr_asc_descContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Order_by_expr_asc_descContext {\n\tvar p = new(Order_by_expr_asc_descContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_order_by_expr_asc_desc\n\n\treturn p\n}\n\nfunc (s *Order_by_expr_asc_descContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Order_by_expr_asc_descContext) ORDER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserORDER_, 0)\n}\n\nfunc (s *Order_by_expr_asc_descContext) BY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBY_, 0)\n}\n\nfunc (s *Order_by_expr_asc_descContext) Expr_asc_desc() IExpr_asc_descContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExpr_asc_descContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExpr_asc_descContext)\n}\n\nfunc (s *Order_by_expr_asc_descContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Order_by_expr_asc_descContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Order_by_expr_asc_descContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterOrder_by_expr_asc_desc(s)\n\t}\n}\n\nfunc (s *Order_by_expr_asc_descContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitOrder_by_expr_asc_desc(s)\n\t}\n}\n\nfunc (s *Order_by_expr_asc_descContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitOrder_by_expr_asc_desc(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Order_by_expr_asc_desc() (localctx IOrder_by_expr_asc_descContext) {\n\tlocalctx = NewOrder_by_expr_asc_descContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 160, ParserRULE_order_by_expr_asc_desc)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1993)\n\t\tp.Match(ParserORDER_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1994)\n\t\tp.Match(ParserBY_)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\t{\n\t\tp.SetState(1995)\n\t\tp.Expr_asc_desc()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IExpr_asc_descContext is an interface to support dynamic dispatch.\ntype IExpr_asc_descContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAllExpr() []IExprContext\n\tExpr(i int) IExprContext\n\tAllAsc_desc() []IAsc_descContext\n\tAsc_desc(i int) IAsc_descContext\n\tAllCOMMA() []antlr.TerminalNode\n\tCOMMA(i int) antlr.TerminalNode\n\n\t// IsExpr_asc_descContext differentiates from other interfaces.\n\tIsExpr_asc_descContext()\n}\n\ntype Expr_asc_descContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyExpr_asc_descContext() *Expr_asc_descContext {\n\tvar p = new(Expr_asc_descContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_expr_asc_desc\n\treturn p\n}\n\nfunc InitEmptyExpr_asc_descContext(p *Expr_asc_descContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_expr_asc_desc\n}\n\nfunc (*Expr_asc_descContext) IsExpr_asc_descContext() {}\n\nfunc NewExpr_asc_descContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Expr_asc_descContext {\n\tvar p = new(Expr_asc_descContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_expr_asc_desc\n\n\treturn p\n}\n\nfunc (s *Expr_asc_descContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Expr_asc_descContext) AllExpr() []IExprContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IExprContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IExprContext); ok {\n\t\t\ttst[i] = t.(IExprContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Expr_asc_descContext) Expr(i int) IExprContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Expr_asc_descContext) AllAsc_desc() []IAsc_descContext {\n\tchildren := s.GetChildren()\n\tlen := 0\n\tfor _, ctx := range children {\n\t\tif _, ok := ctx.(IAsc_descContext); ok {\n\t\t\tlen++\n\t\t}\n\t}\n\n\ttst := make([]IAsc_descContext, len)\n\ti := 0\n\tfor _, ctx := range children {\n\t\tif t, ok := ctx.(IAsc_descContext); ok {\n\t\t\ttst[i] = t.(IAsc_descContext)\n\t\t\ti++\n\t\t}\n\t}\n\n\treturn tst\n}\n\nfunc (s *Expr_asc_descContext) Asc_desc(i int) IAsc_descContext {\n\tvar t antlr.RuleContext\n\tj := 0\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAsc_descContext); ok {\n\t\t\tif j == i {\n\t\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tj++\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAsc_descContext)\n}\n\nfunc (s *Expr_asc_descContext) AllCOMMA() []antlr.TerminalNode {\n\treturn s.GetTokens(ParserCOMMA)\n}\n\nfunc (s *Expr_asc_descContext) COMMA(i int) antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMA, i)\n}\n\nfunc (s *Expr_asc_descContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Expr_asc_descContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Expr_asc_descContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterExpr_asc_desc(s)\n\t}\n}\n\nfunc (s *Expr_asc_descContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitExpr_asc_desc(s)\n\t}\n}\n\nfunc (s *Expr_asc_descContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitExpr_asc_desc(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Expr_asc_desc() (localctx IExpr_asc_descContext) {\n\tlocalctx = NewExpr_asc_descContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 162, ParserRULE_expr_asc_desc)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(1997)\n\t\tp.expr(0)\n\t}\n\tp.SetState(1999)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tif _la == ParserASC_ || _la == ParserDESC_ {\n\t\t{\n\t\t\tp.SetState(1998)\n\t\t\tp.Asc_desc()\n\t\t}\n\n\t}\n\tp.SetState(2008)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\t_la = p.GetTokenStream().LA(1)\n\n\tfor _la == ParserCOMMA {\n\t\t{\n\t\t\tp.SetState(2001)\n\t\t\tp.Match(ParserCOMMA)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(2002)\n\t\t\tp.expr(0)\n\t\t}\n\t\tp.SetState(2004)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif _la == ParserASC_ || _la == ParserDESC_ {\n\t\t\t{\n\t\t\t\tp.SetState(2003)\n\t\t\t\tp.Asc_desc()\n\t\t\t}\n\n\t\t}\n\n\t\tp.SetState(2010)\n\t\tp.GetErrorHandler().Sync(p)\n\t\tif p.HasError() {\n\t\t\tgoto errorExit\n\t\t}\n\t\t_la = p.GetTokenStream().LA(1)\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IInitial_selectContext is an interface to support dynamic dispatch.\ntype IInitial_selectContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tSelect_stmt() ISelect_stmtContext\n\n\t// IsInitial_selectContext differentiates from other interfaces.\n\tIsInitial_selectContext()\n}\n\ntype Initial_selectContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyInitial_selectContext() *Initial_selectContext {\n\tvar p = new(Initial_selectContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_initial_select\n\treturn p\n}\n\nfunc InitEmptyInitial_selectContext(p *Initial_selectContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_initial_select\n}\n\nfunc (*Initial_selectContext) IsInitial_selectContext() {}\n\nfunc NewInitial_selectContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Initial_selectContext {\n\tvar p = new(Initial_selectContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_initial_select\n\n\treturn p\n}\n\nfunc (s *Initial_selectContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Initial_selectContext) Select_stmt() ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *Initial_selectContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Initial_selectContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Initial_selectContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterInitial_select(s)\n\t}\n}\n\nfunc (s *Initial_selectContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitInitial_select(s)\n\t}\n}\n\nfunc (s *Initial_selectContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitInitial_select(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Initial_select() (localctx IInitial_selectContext) {\n\tlocalctx = NewInitial_selectContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 164, ParserRULE_initial_select)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2011)\n\t\tp.Select_stmt()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IRecursive_selectContext is an interface to support dynamic dispatch.\ntype IRecursive_selectContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tSelect_stmt() ISelect_stmtContext\n\n\t// IsRecursive_selectContext differentiates from other interfaces.\n\tIsRecursive_selectContext()\n}\n\ntype Recursive_selectContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyRecursive_selectContext() *Recursive_selectContext {\n\tvar p = new(Recursive_selectContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_recursive_select\n\treturn p\n}\n\nfunc InitEmptyRecursive_selectContext(p *Recursive_selectContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_recursive_select\n}\n\nfunc (*Recursive_selectContext) IsRecursive_selectContext() {}\n\nfunc NewRecursive_selectContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Recursive_selectContext {\n\tvar p = new(Recursive_selectContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_recursive_select\n\n\treturn p\n}\n\nfunc (s *Recursive_selectContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Recursive_selectContext) Select_stmt() ISelect_stmtContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(ISelect_stmtContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(ISelect_stmtContext)\n}\n\nfunc (s *Recursive_selectContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Recursive_selectContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Recursive_selectContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterRecursive_select(s)\n\t}\n}\n\nfunc (s *Recursive_selectContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitRecursive_select(s)\n\t}\n}\n\nfunc (s *Recursive_selectContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitRecursive_select(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Recursive_select() (localctx IRecursive_selectContext) {\n\tlocalctx = NewRecursive_selectContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 166, ParserRULE_recursive_select)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2013)\n\t\tp.Select_stmt()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IUnary_operatorContext is an interface to support dynamic dispatch.\ntype IUnary_operatorContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tMINUS() antlr.TerminalNode\n\tPLUS() antlr.TerminalNode\n\tTILDE() antlr.TerminalNode\n\tNOT_() antlr.TerminalNode\n\n\t// IsUnary_operatorContext differentiates from other interfaces.\n\tIsUnary_operatorContext()\n}\n\ntype Unary_operatorContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyUnary_operatorContext() *Unary_operatorContext {\n\tvar p = new(Unary_operatorContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_unary_operator\n\treturn p\n}\n\nfunc InitEmptyUnary_operatorContext(p *Unary_operatorContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_unary_operator\n}\n\nfunc (*Unary_operatorContext) IsUnary_operatorContext() {}\n\nfunc NewUnary_operatorContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Unary_operatorContext {\n\tvar p = new(Unary_operatorContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_unary_operator\n\n\treturn p\n}\n\nfunc (s *Unary_operatorContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Unary_operatorContext) MINUS() antlr.TerminalNode {\n\treturn s.GetToken(ParserMINUS, 0)\n}\n\nfunc (s *Unary_operatorContext) PLUS() antlr.TerminalNode {\n\treturn s.GetToken(ParserPLUS, 0)\n}\n\nfunc (s *Unary_operatorContext) TILDE() antlr.TerminalNode {\n\treturn s.GetToken(ParserTILDE, 0)\n}\n\nfunc (s *Unary_operatorContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *Unary_operatorContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Unary_operatorContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Unary_operatorContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterUnary_operator(s)\n\t}\n}\n\nfunc (s *Unary_operatorContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitUnary_operator(s)\n\t}\n}\n\nfunc (s *Unary_operatorContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitUnary_operator(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Unary_operator() (localctx IUnary_operatorContext) {\n\tlocalctx = NewUnary_operatorContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 168, ParserRULE_unary_operator)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2015)\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif !(((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&1792) != 0) || _la == ParserNOT_) {\n\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t} else {\n\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\tp.Consume()\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IError_messageContext is an interface to support dynamic dispatch.\ntype IError_messageContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tSTRING_LITERAL() antlr.TerminalNode\n\n\t// IsError_messageContext differentiates from other interfaces.\n\tIsError_messageContext()\n}\n\ntype Error_messageContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyError_messageContext() *Error_messageContext {\n\tvar p = new(Error_messageContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_error_message\n\treturn p\n}\n\nfunc InitEmptyError_messageContext(p *Error_messageContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_error_message\n}\n\nfunc (*Error_messageContext) IsError_messageContext() {}\n\nfunc NewError_messageContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Error_messageContext {\n\tvar p = new(Error_messageContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_error_message\n\n\treturn p\n}\n\nfunc (s *Error_messageContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Error_messageContext) STRING_LITERAL() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTRING_LITERAL, 0)\n}\n\nfunc (s *Error_messageContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Error_messageContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Error_messageContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterError_message(s)\n\t}\n}\n\nfunc (s *Error_messageContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitError_message(s)\n\t}\n}\n\nfunc (s *Error_messageContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitError_message(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Error_message() (localctx IError_messageContext) {\n\tlocalctx = NewError_messageContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 170, ParserRULE_error_message)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2017)\n\t\tp.Match(ParserSTRING_LITERAL)\n\t\tif p.HasError() {\n\t\t\t// Recognition error - abort rule\n\t\t\tgoto errorExit\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IModule_argumentContext is an interface to support dynamic dispatch.\ntype IModule_argumentContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tExpr() IExprContext\n\tColumn_def() IColumn_defContext\n\n\t// IsModule_argumentContext differentiates from other interfaces.\n\tIsModule_argumentContext()\n}\n\ntype Module_argumentContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyModule_argumentContext() *Module_argumentContext {\n\tvar p = new(Module_argumentContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_module_argument\n\treturn p\n}\n\nfunc InitEmptyModule_argumentContext(p *Module_argumentContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_module_argument\n}\n\nfunc (*Module_argumentContext) IsModule_argumentContext() {}\n\nfunc NewModule_argumentContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Module_argumentContext {\n\tvar p = new(Module_argumentContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_module_argument\n\n\treturn p\n}\n\nfunc (s *Module_argumentContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Module_argumentContext) Expr() IExprContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IExprContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IExprContext)\n}\n\nfunc (s *Module_argumentContext) Column_def() IColumn_defContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IColumn_defContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IColumn_defContext)\n}\n\nfunc (s *Module_argumentContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Module_argumentContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Module_argumentContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterModule_argument(s)\n\t}\n}\n\nfunc (s *Module_argumentContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitModule_argument(s)\n\t}\n}\n\nfunc (s *Module_argumentContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitModule_argument(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Module_argument() (localctx IModule_argumentContext) {\n\tlocalctx = NewModule_argumentContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 172, ParserRULE_module_argument)\n\tp.SetState(2021)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 295, p.GetParserRuleContext()) {\n\tcase 1:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(2019)\n\t\t\tp.expr(0)\n\t\t}\n\n\tcase 2:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(2020)\n\t\t\tp.Column_def()\n\t\t}\n\n\tcase antlr.ATNInvalidAltNumber:\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IColumn_aliasContext is an interface to support dynamic dispatch.\ntype IColumn_aliasContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tIDENTIFIER() antlr.TerminalNode\n\tSTRING_LITERAL() antlr.TerminalNode\n\n\t// IsColumn_aliasContext differentiates from other interfaces.\n\tIsColumn_aliasContext()\n}\n\ntype Column_aliasContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyColumn_aliasContext() *Column_aliasContext {\n\tvar p = new(Column_aliasContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_column_alias\n\treturn p\n}\n\nfunc InitEmptyColumn_aliasContext(p *Column_aliasContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_column_alias\n}\n\nfunc (*Column_aliasContext) IsColumn_aliasContext() {}\n\nfunc NewColumn_aliasContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Column_aliasContext {\n\tvar p = new(Column_aliasContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_column_alias\n\n\treturn p\n}\n\nfunc (s *Column_aliasContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Column_aliasContext) IDENTIFIER() antlr.TerminalNode {\n\treturn s.GetToken(ParserIDENTIFIER, 0)\n}\n\nfunc (s *Column_aliasContext) STRING_LITERAL() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTRING_LITERAL, 0)\n}\n\nfunc (s *Column_aliasContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Column_aliasContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Column_aliasContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterColumn_alias(s)\n\t}\n}\n\nfunc (s *Column_aliasContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitColumn_alias(s)\n\t}\n}\n\nfunc (s *Column_aliasContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitColumn_alias(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Column_alias() (localctx IColumn_aliasContext) {\n\tlocalctx = NewColumn_aliasContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 174, ParserRULE_column_alias)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2023)\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif !(_la == ParserIDENTIFIER || _la == ParserSTRING_LITERAL) {\n\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t} else {\n\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\tp.Consume()\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IKeywordContext is an interface to support dynamic dispatch.\ntype IKeywordContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tABORT_() antlr.TerminalNode\n\tACTION_() antlr.TerminalNode\n\tADD_() antlr.TerminalNode\n\tAFTER_() antlr.TerminalNode\n\tALL_() antlr.TerminalNode\n\tALTER_() antlr.TerminalNode\n\tANALYZE_() antlr.TerminalNode\n\tAND_() antlr.TerminalNode\n\tAS_() antlr.TerminalNode\n\tASC_() antlr.TerminalNode\n\tATTACH_() antlr.TerminalNode\n\tAUTOINCREMENT_() antlr.TerminalNode\n\tBEFORE_() antlr.TerminalNode\n\tBEGIN_() antlr.TerminalNode\n\tBETWEEN_() antlr.TerminalNode\n\tBY_() antlr.TerminalNode\n\tCASCADE_() antlr.TerminalNode\n\tCASE_() antlr.TerminalNode\n\tCAST_() antlr.TerminalNode\n\tCHECK_() antlr.TerminalNode\n\tCOLLATE_() antlr.TerminalNode\n\tCOLUMN_() antlr.TerminalNode\n\tCOMMIT_() antlr.TerminalNode\n\tCONFLICT_() antlr.TerminalNode\n\tCONSTRAINT_() antlr.TerminalNode\n\tCREATE_() antlr.TerminalNode\n\tCROSS_() antlr.TerminalNode\n\tCURRENT_DATE_() antlr.TerminalNode\n\tCURRENT_TIME_() antlr.TerminalNode\n\tCURRENT_TIMESTAMP_() antlr.TerminalNode\n\tDATABASE_() antlr.TerminalNode\n\tDEFAULT_() antlr.TerminalNode\n\tDEFERRABLE_() antlr.TerminalNode\n\tDEFERRED_() antlr.TerminalNode\n\tDELETE_() antlr.TerminalNode\n\tDESC_() antlr.TerminalNode\n\tDETACH_() antlr.TerminalNode\n\tDISTINCT_() antlr.TerminalNode\n\tDROP_() antlr.TerminalNode\n\tEACH_() antlr.TerminalNode\n\tELSE_() antlr.TerminalNode\n\tEND_() antlr.TerminalNode\n\tESCAPE_() antlr.TerminalNode\n\tEXCEPT_() antlr.TerminalNode\n\tEXCLUSIVE_() antlr.TerminalNode\n\tEXISTS_() antlr.TerminalNode\n\tEXPLAIN_() antlr.TerminalNode\n\tFAIL_() antlr.TerminalNode\n\tFOR_() antlr.TerminalNode\n\tFOREIGN_() antlr.TerminalNode\n\tFROM_() antlr.TerminalNode\n\tFULL_() antlr.TerminalNode\n\tGLOB_() antlr.TerminalNode\n\tGROUP_() antlr.TerminalNode\n\tHAVING_() antlr.TerminalNode\n\tIF_() antlr.TerminalNode\n\tIGNORE_() antlr.TerminalNode\n\tIMMEDIATE_() antlr.TerminalNode\n\tIN_() antlr.TerminalNode\n\tINDEX_() antlr.TerminalNode\n\tINDEXED_() antlr.TerminalNode\n\tINITIALLY_() antlr.TerminalNode\n\tINNER_() antlr.TerminalNode\n\tINSERT_() antlr.TerminalNode\n\tINSTEAD_() antlr.TerminalNode\n\tINTERSECT_() antlr.TerminalNode\n\tINTO_() antlr.TerminalNode\n\tIS_() antlr.TerminalNode\n\tISNULL_() antlr.TerminalNode\n\tJOIN_() antlr.TerminalNode\n\tKEY_() antlr.TerminalNode\n\tLEFT_() antlr.TerminalNode\n\tLIKE_() antlr.TerminalNode\n\tLIMIT_() antlr.TerminalNode\n\tMATCH_() antlr.TerminalNode\n\tNATURAL_() antlr.TerminalNode\n\tNO_() antlr.TerminalNode\n\tNOT_() antlr.TerminalNode\n\tNOTNULL_() antlr.TerminalNode\n\tNULL_() antlr.TerminalNode\n\tOF_() antlr.TerminalNode\n\tOFFSET_() antlr.TerminalNode\n\tON_() antlr.TerminalNode\n\tOR_() antlr.TerminalNode\n\tORDER_() antlr.TerminalNode\n\tOUTER_() antlr.TerminalNode\n\tPLAN_() antlr.TerminalNode\n\tPRAGMA_() antlr.TerminalNode\n\tPRIMARY_() antlr.TerminalNode\n\tQUERY_() antlr.TerminalNode\n\tRAISE_() antlr.TerminalNode\n\tRECURSIVE_() antlr.TerminalNode\n\tREFERENCES_() antlr.TerminalNode\n\tREGEXP_() antlr.TerminalNode\n\tREINDEX_() antlr.TerminalNode\n\tRELEASE_() antlr.TerminalNode\n\tRENAME_() antlr.TerminalNode\n\tREPLACE_() antlr.TerminalNode\n\tRESTRICT_() antlr.TerminalNode\n\tRIGHT_() antlr.TerminalNode\n\tROLLBACK_() antlr.TerminalNode\n\tROW_() antlr.TerminalNode\n\tROWS_() antlr.TerminalNode\n\tSAVEPOINT_() antlr.TerminalNode\n\tSELECT_() antlr.TerminalNode\n\tSET_() antlr.TerminalNode\n\tTABLE_() antlr.TerminalNode\n\tTEMP_() antlr.TerminalNode\n\tTEMPORARY_() antlr.TerminalNode\n\tTHEN_() antlr.TerminalNode\n\tTO_() antlr.TerminalNode\n\tTRANSACTION_() antlr.TerminalNode\n\tTRIGGER_() antlr.TerminalNode\n\tUNION_() antlr.TerminalNode\n\tUNIQUE_() antlr.TerminalNode\n\tUPDATE_() antlr.TerminalNode\n\tUSING_() antlr.TerminalNode\n\tVACUUM_() antlr.TerminalNode\n\tVALUES_() antlr.TerminalNode\n\tVIEW_() antlr.TerminalNode\n\tVIRTUAL_() antlr.TerminalNode\n\tWHEN_() antlr.TerminalNode\n\tWHERE_() antlr.TerminalNode\n\tWITH_() antlr.TerminalNode\n\tWITHOUT_() antlr.TerminalNode\n\tFIRST_VALUE_() antlr.TerminalNode\n\tOVER_() antlr.TerminalNode\n\tPARTITION_() antlr.TerminalNode\n\tRANGE_() antlr.TerminalNode\n\tPRECEDING_() antlr.TerminalNode\n\tUNBOUNDED_() antlr.TerminalNode\n\tCURRENT_() antlr.TerminalNode\n\tFOLLOWING_() antlr.TerminalNode\n\tCUME_DIST_() antlr.TerminalNode\n\tDENSE_RANK_() antlr.TerminalNode\n\tLAG_() antlr.TerminalNode\n\tLAST_VALUE_() antlr.TerminalNode\n\tLEAD_() antlr.TerminalNode\n\tNTH_VALUE_() antlr.TerminalNode\n\tNTILE_() antlr.TerminalNode\n\tPERCENT_RANK_() antlr.TerminalNode\n\tRANK_() antlr.TerminalNode\n\tROW_NUMBER_() antlr.TerminalNode\n\tGENERATED_() antlr.TerminalNode\n\tALWAYS_() antlr.TerminalNode\n\tSTORED_() antlr.TerminalNode\n\tTRUE_() antlr.TerminalNode\n\tFALSE_() antlr.TerminalNode\n\tWINDOW_() antlr.TerminalNode\n\tNULLS_() antlr.TerminalNode\n\tFIRST_() antlr.TerminalNode\n\tLAST_() antlr.TerminalNode\n\tFILTER_() antlr.TerminalNode\n\tGROUPS_() antlr.TerminalNode\n\tEXCLUDE_() antlr.TerminalNode\n\n\t// IsKeywordContext differentiates from other interfaces.\n\tIsKeywordContext()\n}\n\ntype KeywordContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyKeywordContext() *KeywordContext {\n\tvar p = new(KeywordContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_keyword\n\treturn p\n}\n\nfunc InitEmptyKeywordContext(p *KeywordContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_keyword\n}\n\nfunc (*KeywordContext) IsKeywordContext() {}\n\nfunc NewKeywordContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *KeywordContext {\n\tvar p = new(KeywordContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_keyword\n\n\treturn p\n}\n\nfunc (s *KeywordContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *KeywordContext) ABORT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserABORT_, 0)\n}\n\nfunc (s *KeywordContext) ACTION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserACTION_, 0)\n}\n\nfunc (s *KeywordContext) ADD_() antlr.TerminalNode {\n\treturn s.GetToken(ParserADD_, 0)\n}\n\nfunc (s *KeywordContext) AFTER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAFTER_, 0)\n}\n\nfunc (s *KeywordContext) ALL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserALL_, 0)\n}\n\nfunc (s *KeywordContext) ALTER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserALTER_, 0)\n}\n\nfunc (s *KeywordContext) ANALYZE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserANALYZE_, 0)\n}\n\nfunc (s *KeywordContext) AND_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAND_, 0)\n}\n\nfunc (s *KeywordContext) AS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAS_, 0)\n}\n\nfunc (s *KeywordContext) ASC_() antlr.TerminalNode {\n\treturn s.GetToken(ParserASC_, 0)\n}\n\nfunc (s *KeywordContext) ATTACH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserATTACH_, 0)\n}\n\nfunc (s *KeywordContext) AUTOINCREMENT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserAUTOINCREMENT_, 0)\n}\n\nfunc (s *KeywordContext) BEFORE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBEFORE_, 0)\n}\n\nfunc (s *KeywordContext) BEGIN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBEGIN_, 0)\n}\n\nfunc (s *KeywordContext) BETWEEN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBETWEEN_, 0)\n}\n\nfunc (s *KeywordContext) BY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserBY_, 0)\n}\n\nfunc (s *KeywordContext) CASCADE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCASCADE_, 0)\n}\n\nfunc (s *KeywordContext) CASE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCASE_, 0)\n}\n\nfunc (s *KeywordContext) CAST_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCAST_, 0)\n}\n\nfunc (s *KeywordContext) CHECK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCHECK_, 0)\n}\n\nfunc (s *KeywordContext) COLLATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOLLATE_, 0)\n}\n\nfunc (s *KeywordContext) COLUMN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOLUMN_, 0)\n}\n\nfunc (s *KeywordContext) COMMIT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCOMMIT_, 0)\n}\n\nfunc (s *KeywordContext) CONFLICT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCONFLICT_, 0)\n}\n\nfunc (s *KeywordContext) CONSTRAINT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCONSTRAINT_, 0)\n}\n\nfunc (s *KeywordContext) CREATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCREATE_, 0)\n}\n\nfunc (s *KeywordContext) CROSS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCROSS_, 0)\n}\n\nfunc (s *KeywordContext) CURRENT_DATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_DATE_, 0)\n}\n\nfunc (s *KeywordContext) CURRENT_TIME_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_TIME_, 0)\n}\n\nfunc (s *KeywordContext) CURRENT_TIMESTAMP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_TIMESTAMP_, 0)\n}\n\nfunc (s *KeywordContext) DATABASE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDATABASE_, 0)\n}\n\nfunc (s *KeywordContext) DEFAULT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDEFAULT_, 0)\n}\n\nfunc (s *KeywordContext) DEFERRABLE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDEFERRABLE_, 0)\n}\n\nfunc (s *KeywordContext) DEFERRED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDEFERRED_, 0)\n}\n\nfunc (s *KeywordContext) DELETE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDELETE_, 0)\n}\n\nfunc (s *KeywordContext) DESC_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDESC_, 0)\n}\n\nfunc (s *KeywordContext) DETACH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDETACH_, 0)\n}\n\nfunc (s *KeywordContext) DISTINCT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDISTINCT_, 0)\n}\n\nfunc (s *KeywordContext) DROP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDROP_, 0)\n}\n\nfunc (s *KeywordContext) EACH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEACH_, 0)\n}\n\nfunc (s *KeywordContext) ELSE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserELSE_, 0)\n}\n\nfunc (s *KeywordContext) END_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEND_, 0)\n}\n\nfunc (s *KeywordContext) ESCAPE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserESCAPE_, 0)\n}\n\nfunc (s *KeywordContext) EXCEPT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXCEPT_, 0)\n}\n\nfunc (s *KeywordContext) EXCLUSIVE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXCLUSIVE_, 0)\n}\n\nfunc (s *KeywordContext) EXISTS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXISTS_, 0)\n}\n\nfunc (s *KeywordContext) EXPLAIN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXPLAIN_, 0)\n}\n\nfunc (s *KeywordContext) FAIL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFAIL_, 0)\n}\n\nfunc (s *KeywordContext) FOR_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFOR_, 0)\n}\n\nfunc (s *KeywordContext) FOREIGN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFOREIGN_, 0)\n}\n\nfunc (s *KeywordContext) FROM_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFROM_, 0)\n}\n\nfunc (s *KeywordContext) FULL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFULL_, 0)\n}\n\nfunc (s *KeywordContext) GLOB_() antlr.TerminalNode {\n\treturn s.GetToken(ParserGLOB_, 0)\n}\n\nfunc (s *KeywordContext) GROUP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserGROUP_, 0)\n}\n\nfunc (s *KeywordContext) HAVING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserHAVING_, 0)\n}\n\nfunc (s *KeywordContext) IF_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIF_, 0)\n}\n\nfunc (s *KeywordContext) IGNORE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIGNORE_, 0)\n}\n\nfunc (s *KeywordContext) IMMEDIATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIMMEDIATE_, 0)\n}\n\nfunc (s *KeywordContext) IN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIN_, 0)\n}\n\nfunc (s *KeywordContext) INDEX_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINDEX_, 0)\n}\n\nfunc (s *KeywordContext) INDEXED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINDEXED_, 0)\n}\n\nfunc (s *KeywordContext) INITIALLY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINITIALLY_, 0)\n}\n\nfunc (s *KeywordContext) INNER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINNER_, 0)\n}\n\nfunc (s *KeywordContext) INSERT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINSERT_, 0)\n}\n\nfunc (s *KeywordContext) INSTEAD_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINSTEAD_, 0)\n}\n\nfunc (s *KeywordContext) INTERSECT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINTERSECT_, 0)\n}\n\nfunc (s *KeywordContext) INTO_() antlr.TerminalNode {\n\treturn s.GetToken(ParserINTO_, 0)\n}\n\nfunc (s *KeywordContext) IS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserIS_, 0)\n}\n\nfunc (s *KeywordContext) ISNULL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserISNULL_, 0)\n}\n\nfunc (s *KeywordContext) JOIN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserJOIN_, 0)\n}\n\nfunc (s *KeywordContext) KEY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserKEY_, 0)\n}\n\nfunc (s *KeywordContext) LEFT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLEFT_, 0)\n}\n\nfunc (s *KeywordContext) LIKE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLIKE_, 0)\n}\n\nfunc (s *KeywordContext) LIMIT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLIMIT_, 0)\n}\n\nfunc (s *KeywordContext) MATCH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserMATCH_, 0)\n}\n\nfunc (s *KeywordContext) NATURAL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNATURAL_, 0)\n}\n\nfunc (s *KeywordContext) NO_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNO_, 0)\n}\n\nfunc (s *KeywordContext) NOT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOT_, 0)\n}\n\nfunc (s *KeywordContext) NOTNULL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNOTNULL_, 0)\n}\n\nfunc (s *KeywordContext) NULL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNULL_, 0)\n}\n\nfunc (s *KeywordContext) OF_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOF_, 0)\n}\n\nfunc (s *KeywordContext) OFFSET_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOFFSET_, 0)\n}\n\nfunc (s *KeywordContext) ON_() antlr.TerminalNode {\n\treturn s.GetToken(ParserON_, 0)\n}\n\nfunc (s *KeywordContext) OR_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOR_, 0)\n}\n\nfunc (s *KeywordContext) ORDER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserORDER_, 0)\n}\n\nfunc (s *KeywordContext) OUTER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOUTER_, 0)\n}\n\nfunc (s *KeywordContext) PLAN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPLAN_, 0)\n}\n\nfunc (s *KeywordContext) PRAGMA_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPRAGMA_, 0)\n}\n\nfunc (s *KeywordContext) PRIMARY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPRIMARY_, 0)\n}\n\nfunc (s *KeywordContext) QUERY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserQUERY_, 0)\n}\n\nfunc (s *KeywordContext) RAISE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRAISE_, 0)\n}\n\nfunc (s *KeywordContext) RECURSIVE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRECURSIVE_, 0)\n}\n\nfunc (s *KeywordContext) REFERENCES_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREFERENCES_, 0)\n}\n\nfunc (s *KeywordContext) REGEXP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREGEXP_, 0)\n}\n\nfunc (s *KeywordContext) REINDEX_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREINDEX_, 0)\n}\n\nfunc (s *KeywordContext) RELEASE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRELEASE_, 0)\n}\n\nfunc (s *KeywordContext) RENAME_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRENAME_, 0)\n}\n\nfunc (s *KeywordContext) REPLACE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserREPLACE_, 0)\n}\n\nfunc (s *KeywordContext) RESTRICT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRESTRICT_, 0)\n}\n\nfunc (s *KeywordContext) RIGHT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRIGHT_, 0)\n}\n\nfunc (s *KeywordContext) ROLLBACK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROLLBACK_, 0)\n}\n\nfunc (s *KeywordContext) ROW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROW_, 0)\n}\n\nfunc (s *KeywordContext) ROWS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROWS_, 0)\n}\n\nfunc (s *KeywordContext) SAVEPOINT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSAVEPOINT_, 0)\n}\n\nfunc (s *KeywordContext) SELECT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSELECT_, 0)\n}\n\nfunc (s *KeywordContext) SET_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSET_, 0)\n}\n\nfunc (s *KeywordContext) TABLE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTABLE_, 0)\n}\n\nfunc (s *KeywordContext) TEMP_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTEMP_, 0)\n}\n\nfunc (s *KeywordContext) TEMPORARY_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTEMPORARY_, 0)\n}\n\nfunc (s *KeywordContext) THEN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTHEN_, 0)\n}\n\nfunc (s *KeywordContext) TO_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTO_, 0)\n}\n\nfunc (s *KeywordContext) TRANSACTION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTRANSACTION_, 0)\n}\n\nfunc (s *KeywordContext) TRIGGER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTRIGGER_, 0)\n}\n\nfunc (s *KeywordContext) UNION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNION_, 0)\n}\n\nfunc (s *KeywordContext) UNIQUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNIQUE_, 0)\n}\n\nfunc (s *KeywordContext) UPDATE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUPDATE_, 0)\n}\n\nfunc (s *KeywordContext) USING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUSING_, 0)\n}\n\nfunc (s *KeywordContext) VACUUM_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVACUUM_, 0)\n}\n\nfunc (s *KeywordContext) VALUES_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVALUES_, 0)\n}\n\nfunc (s *KeywordContext) VIEW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVIEW_, 0)\n}\n\nfunc (s *KeywordContext) VIRTUAL_() antlr.TerminalNode {\n\treturn s.GetToken(ParserVIRTUAL_, 0)\n}\n\nfunc (s *KeywordContext) WHEN_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWHEN_, 0)\n}\n\nfunc (s *KeywordContext) WHERE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWHERE_, 0)\n}\n\nfunc (s *KeywordContext) WITH_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWITH_, 0)\n}\n\nfunc (s *KeywordContext) WITHOUT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWITHOUT_, 0)\n}\n\nfunc (s *KeywordContext) FIRST_VALUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFIRST_VALUE_, 0)\n}\n\nfunc (s *KeywordContext) OVER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserOVER_, 0)\n}\n\nfunc (s *KeywordContext) PARTITION_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPARTITION_, 0)\n}\n\nfunc (s *KeywordContext) RANGE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRANGE_, 0)\n}\n\nfunc (s *KeywordContext) PRECEDING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPRECEDING_, 0)\n}\n\nfunc (s *KeywordContext) UNBOUNDED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserUNBOUNDED_, 0)\n}\n\nfunc (s *KeywordContext) CURRENT_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCURRENT_, 0)\n}\n\nfunc (s *KeywordContext) FOLLOWING_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFOLLOWING_, 0)\n}\n\nfunc (s *KeywordContext) CUME_DIST_() antlr.TerminalNode {\n\treturn s.GetToken(ParserCUME_DIST_, 0)\n}\n\nfunc (s *KeywordContext) DENSE_RANK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserDENSE_RANK_, 0)\n}\n\nfunc (s *KeywordContext) LAG_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLAG_, 0)\n}\n\nfunc (s *KeywordContext) LAST_VALUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLAST_VALUE_, 0)\n}\n\nfunc (s *KeywordContext) LEAD_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLEAD_, 0)\n}\n\nfunc (s *KeywordContext) NTH_VALUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNTH_VALUE_, 0)\n}\n\nfunc (s *KeywordContext) NTILE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNTILE_, 0)\n}\n\nfunc (s *KeywordContext) PERCENT_RANK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserPERCENT_RANK_, 0)\n}\n\nfunc (s *KeywordContext) RANK_() antlr.TerminalNode {\n\treturn s.GetToken(ParserRANK_, 0)\n}\n\nfunc (s *KeywordContext) ROW_NUMBER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserROW_NUMBER_, 0)\n}\n\nfunc (s *KeywordContext) GENERATED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserGENERATED_, 0)\n}\n\nfunc (s *KeywordContext) ALWAYS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserALWAYS_, 0)\n}\n\nfunc (s *KeywordContext) STORED_() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTORED_, 0)\n}\n\nfunc (s *KeywordContext) TRUE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserTRUE_, 0)\n}\n\nfunc (s *KeywordContext) FALSE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFALSE_, 0)\n}\n\nfunc (s *KeywordContext) WINDOW_() antlr.TerminalNode {\n\treturn s.GetToken(ParserWINDOW_, 0)\n}\n\nfunc (s *KeywordContext) NULLS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserNULLS_, 0)\n}\n\nfunc (s *KeywordContext) FIRST_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFIRST_, 0)\n}\n\nfunc (s *KeywordContext) LAST_() antlr.TerminalNode {\n\treturn s.GetToken(ParserLAST_, 0)\n}\n\nfunc (s *KeywordContext) FILTER_() antlr.TerminalNode {\n\treturn s.GetToken(ParserFILTER_, 0)\n}\n\nfunc (s *KeywordContext) GROUPS_() antlr.TerminalNode {\n\treturn s.GetToken(ParserGROUPS_, 0)\n}\n\nfunc (s *KeywordContext) EXCLUDE_() antlr.TerminalNode {\n\treturn s.GetToken(ParserEXCLUDE_, 0)\n}\n\nfunc (s *KeywordContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *KeywordContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *KeywordContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterKeyword(s)\n\t}\n}\n\nfunc (s *KeywordContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitKeyword(s)\n\t}\n}\n\nfunc (s *KeywordContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitKeyword(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Keyword() (localctx IKeywordContext) {\n\tlocalctx = NewKeywordContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 176, ParserRULE_keyword)\n\tvar _la int\n\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2025)\n\t\t_la = p.GetTokenStream().LA(1)\n\n\t\tif !(((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)) {\n\t\t\tp.GetErrorHandler().RecoverInline(p)\n\t\t} else {\n\t\t\tp.GetErrorHandler().ReportMatch(p)\n\t\t\tp.Consume()\n\t\t}\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// INameContext is an interface to support dynamic dispatch.\ntype INameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsNameContext differentiates from other interfaces.\n\tIsNameContext()\n}\n\ntype NameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyNameContext() *NameContext {\n\tvar p = new(NameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_name\n\treturn p\n}\n\nfunc InitEmptyNameContext(p *NameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_name\n}\n\nfunc (*NameContext) IsNameContext() {}\n\nfunc NewNameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *NameContext {\n\tvar p = new(NameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_name\n\n\treturn p\n}\n\nfunc (s *NameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *NameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *NameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *NameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *NameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterName(s)\n\t}\n}\n\nfunc (s *NameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitName(s)\n\t}\n}\n\nfunc (s *NameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitName(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Name() (localctx INameContext) {\n\tlocalctx = NewNameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 178, ParserRULE_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2027)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IFunction_nameContext is an interface to support dynamic dispatch.\ntype IFunction_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsFunction_nameContext differentiates from other interfaces.\n\tIsFunction_nameContext()\n}\n\ntype Function_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyFunction_nameContext() *Function_nameContext {\n\tvar p = new(Function_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_function_name\n\treturn p\n}\n\nfunc InitEmptyFunction_nameContext(p *Function_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_function_name\n}\n\nfunc (*Function_nameContext) IsFunction_nameContext() {}\n\nfunc NewFunction_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Function_nameContext {\n\tvar p = new(Function_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_function_name\n\n\treturn p\n}\n\nfunc (s *Function_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Function_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Function_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Function_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Function_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterFunction_name(s)\n\t}\n}\n\nfunc (s *Function_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitFunction_name(s)\n\t}\n}\n\nfunc (s *Function_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitFunction_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Function_name() (localctx IFunction_nameContext) {\n\tlocalctx = NewFunction_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 180, ParserRULE_function_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2029)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISchema_nameContext is an interface to support dynamic dispatch.\ntype ISchema_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsSchema_nameContext differentiates from other interfaces.\n\tIsSchema_nameContext()\n}\n\ntype Schema_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySchema_nameContext() *Schema_nameContext {\n\tvar p = new(Schema_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_schema_name\n\treturn p\n}\n\nfunc InitEmptySchema_nameContext(p *Schema_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_schema_name\n}\n\nfunc (*Schema_nameContext) IsSchema_nameContext() {}\n\nfunc NewSchema_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Schema_nameContext {\n\tvar p = new(Schema_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_schema_name\n\n\treturn p\n}\n\nfunc (s *Schema_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Schema_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Schema_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Schema_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Schema_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSchema_name(s)\n\t}\n}\n\nfunc (s *Schema_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSchema_name(s)\n\t}\n}\n\nfunc (s *Schema_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSchema_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Schema_name() (localctx ISchema_nameContext) {\n\tlocalctx = NewSchema_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 182, ParserRULE_schema_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2031)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ITable_nameContext is an interface to support dynamic dispatch.\ntype ITable_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsTable_nameContext differentiates from other interfaces.\n\tIsTable_nameContext()\n}\n\ntype Table_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyTable_nameContext() *Table_nameContext {\n\tvar p = new(Table_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_name\n\treturn p\n}\n\nfunc InitEmptyTable_nameContext(p *Table_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_name\n}\n\nfunc (*Table_nameContext) IsTable_nameContext() {}\n\nfunc NewTable_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_nameContext {\n\tvar p = new(Table_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_table_name\n\n\treturn p\n}\n\nfunc (s *Table_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Table_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Table_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Table_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Table_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterTable_name(s)\n\t}\n}\n\nfunc (s *Table_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitTable_name(s)\n\t}\n}\n\nfunc (s *Table_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitTable_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Table_name() (localctx ITable_nameContext) {\n\tlocalctx = NewTable_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 184, ParserRULE_table_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2033)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ITable_or_index_nameContext is an interface to support dynamic dispatch.\ntype ITable_or_index_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsTable_or_index_nameContext differentiates from other interfaces.\n\tIsTable_or_index_nameContext()\n}\n\ntype Table_or_index_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyTable_or_index_nameContext() *Table_or_index_nameContext {\n\tvar p = new(Table_or_index_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_or_index_name\n\treturn p\n}\n\nfunc InitEmptyTable_or_index_nameContext(p *Table_or_index_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_or_index_name\n}\n\nfunc (*Table_or_index_nameContext) IsTable_or_index_nameContext() {}\n\nfunc NewTable_or_index_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_or_index_nameContext {\n\tvar p = new(Table_or_index_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_table_or_index_name\n\n\treturn p\n}\n\nfunc (s *Table_or_index_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Table_or_index_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Table_or_index_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Table_or_index_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Table_or_index_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterTable_or_index_name(s)\n\t}\n}\n\nfunc (s *Table_or_index_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitTable_or_index_name(s)\n\t}\n}\n\nfunc (s *Table_or_index_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitTable_or_index_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Table_or_index_name() (localctx ITable_or_index_nameContext) {\n\tlocalctx = NewTable_or_index_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 186, ParserRULE_table_or_index_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2035)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IColumn_nameContext is an interface to support dynamic dispatch.\ntype IColumn_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsColumn_nameContext differentiates from other interfaces.\n\tIsColumn_nameContext()\n}\n\ntype Column_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyColumn_nameContext() *Column_nameContext {\n\tvar p = new(Column_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_column_name\n\treturn p\n}\n\nfunc InitEmptyColumn_nameContext(p *Column_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_column_name\n}\n\nfunc (*Column_nameContext) IsColumn_nameContext() {}\n\nfunc NewColumn_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Column_nameContext {\n\tvar p = new(Column_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_column_name\n\n\treturn p\n}\n\nfunc (s *Column_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Column_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Column_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Column_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Column_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterColumn_name(s)\n\t}\n}\n\nfunc (s *Column_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitColumn_name(s)\n\t}\n}\n\nfunc (s *Column_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitColumn_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Column_name() (localctx IColumn_nameContext) {\n\tlocalctx = NewColumn_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 188, ParserRULE_column_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2037)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ICollation_nameContext is an interface to support dynamic dispatch.\ntype ICollation_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsCollation_nameContext differentiates from other interfaces.\n\tIsCollation_nameContext()\n}\n\ntype Collation_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyCollation_nameContext() *Collation_nameContext {\n\tvar p = new(Collation_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_collation_name\n\treturn p\n}\n\nfunc InitEmptyCollation_nameContext(p *Collation_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_collation_name\n}\n\nfunc (*Collation_nameContext) IsCollation_nameContext() {}\n\nfunc NewCollation_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Collation_nameContext {\n\tvar p = new(Collation_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_collation_name\n\n\treturn p\n}\n\nfunc (s *Collation_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Collation_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Collation_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Collation_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Collation_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterCollation_name(s)\n\t}\n}\n\nfunc (s *Collation_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitCollation_name(s)\n\t}\n}\n\nfunc (s *Collation_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitCollation_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Collation_name() (localctx ICollation_nameContext) {\n\tlocalctx = NewCollation_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 190, ParserRULE_collation_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2039)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IForeign_tableContext is an interface to support dynamic dispatch.\ntype IForeign_tableContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsForeign_tableContext differentiates from other interfaces.\n\tIsForeign_tableContext()\n}\n\ntype Foreign_tableContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyForeign_tableContext() *Foreign_tableContext {\n\tvar p = new(Foreign_tableContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_foreign_table\n\treturn p\n}\n\nfunc InitEmptyForeign_tableContext(p *Foreign_tableContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_foreign_table\n}\n\nfunc (*Foreign_tableContext) IsForeign_tableContext() {}\n\nfunc NewForeign_tableContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Foreign_tableContext {\n\tvar p = new(Foreign_tableContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_foreign_table\n\n\treturn p\n}\n\nfunc (s *Foreign_tableContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Foreign_tableContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Foreign_tableContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Foreign_tableContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Foreign_tableContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterForeign_table(s)\n\t}\n}\n\nfunc (s *Foreign_tableContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitForeign_table(s)\n\t}\n}\n\nfunc (s *Foreign_tableContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitForeign_table(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Foreign_table() (localctx IForeign_tableContext) {\n\tlocalctx = NewForeign_tableContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 192, ParserRULE_foreign_table)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2041)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IIndex_nameContext is an interface to support dynamic dispatch.\ntype IIndex_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsIndex_nameContext differentiates from other interfaces.\n\tIsIndex_nameContext()\n}\n\ntype Index_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyIndex_nameContext() *Index_nameContext {\n\tvar p = new(Index_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_index_name\n\treturn p\n}\n\nfunc InitEmptyIndex_nameContext(p *Index_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_index_name\n}\n\nfunc (*Index_nameContext) IsIndex_nameContext() {}\n\nfunc NewIndex_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Index_nameContext {\n\tvar p = new(Index_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_index_name\n\n\treturn p\n}\n\nfunc (s *Index_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Index_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Index_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Index_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Index_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterIndex_name(s)\n\t}\n}\n\nfunc (s *Index_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitIndex_name(s)\n\t}\n}\n\nfunc (s *Index_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitIndex_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Index_name() (localctx IIndex_nameContext) {\n\tlocalctx = NewIndex_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 194, ParserRULE_index_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2043)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ITrigger_nameContext is an interface to support dynamic dispatch.\ntype ITrigger_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsTrigger_nameContext differentiates from other interfaces.\n\tIsTrigger_nameContext()\n}\n\ntype Trigger_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyTrigger_nameContext() *Trigger_nameContext {\n\tvar p = new(Trigger_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_trigger_name\n\treturn p\n}\n\nfunc InitEmptyTrigger_nameContext(p *Trigger_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_trigger_name\n}\n\nfunc (*Trigger_nameContext) IsTrigger_nameContext() {}\n\nfunc NewTrigger_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Trigger_nameContext {\n\tvar p = new(Trigger_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_trigger_name\n\n\treturn p\n}\n\nfunc (s *Trigger_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Trigger_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Trigger_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Trigger_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Trigger_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterTrigger_name(s)\n\t}\n}\n\nfunc (s *Trigger_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitTrigger_name(s)\n\t}\n}\n\nfunc (s *Trigger_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitTrigger_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Trigger_name() (localctx ITrigger_nameContext) {\n\tlocalctx = NewTrigger_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 196, ParserRULE_trigger_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2045)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IView_nameContext is an interface to support dynamic dispatch.\ntype IView_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsView_nameContext differentiates from other interfaces.\n\tIsView_nameContext()\n}\n\ntype View_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyView_nameContext() *View_nameContext {\n\tvar p = new(View_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_view_name\n\treturn p\n}\n\nfunc InitEmptyView_nameContext(p *View_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_view_name\n}\n\nfunc (*View_nameContext) IsView_nameContext() {}\n\nfunc NewView_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *View_nameContext {\n\tvar p = new(View_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_view_name\n\n\treturn p\n}\n\nfunc (s *View_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *View_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *View_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *View_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *View_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterView_name(s)\n\t}\n}\n\nfunc (s *View_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitView_name(s)\n\t}\n}\n\nfunc (s *View_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitView_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) View_name() (localctx IView_nameContext) {\n\tlocalctx = NewView_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 198, ParserRULE_view_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2047)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IModule_nameContext is an interface to support dynamic dispatch.\ntype IModule_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsModule_nameContext differentiates from other interfaces.\n\tIsModule_nameContext()\n}\n\ntype Module_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyModule_nameContext() *Module_nameContext {\n\tvar p = new(Module_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_module_name\n\treturn p\n}\n\nfunc InitEmptyModule_nameContext(p *Module_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_module_name\n}\n\nfunc (*Module_nameContext) IsModule_nameContext() {}\n\nfunc NewModule_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Module_nameContext {\n\tvar p = new(Module_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_module_name\n\n\treturn p\n}\n\nfunc (s *Module_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Module_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Module_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Module_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Module_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterModule_name(s)\n\t}\n}\n\nfunc (s *Module_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitModule_name(s)\n\t}\n}\n\nfunc (s *Module_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitModule_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Module_name() (localctx IModule_nameContext) {\n\tlocalctx = NewModule_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 200, ParserRULE_module_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2049)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IPragma_nameContext is an interface to support dynamic dispatch.\ntype IPragma_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsPragma_nameContext differentiates from other interfaces.\n\tIsPragma_nameContext()\n}\n\ntype Pragma_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyPragma_nameContext() *Pragma_nameContext {\n\tvar p = new(Pragma_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_pragma_name\n\treturn p\n}\n\nfunc InitEmptyPragma_nameContext(p *Pragma_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_pragma_name\n}\n\nfunc (*Pragma_nameContext) IsPragma_nameContext() {}\n\nfunc NewPragma_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Pragma_nameContext {\n\tvar p = new(Pragma_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_pragma_name\n\n\treturn p\n}\n\nfunc (s *Pragma_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Pragma_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Pragma_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Pragma_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Pragma_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterPragma_name(s)\n\t}\n}\n\nfunc (s *Pragma_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitPragma_name(s)\n\t}\n}\n\nfunc (s *Pragma_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitPragma_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Pragma_name() (localctx IPragma_nameContext) {\n\tlocalctx = NewPragma_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 202, ParserRULE_pragma_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2051)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISavepoint_nameContext is an interface to support dynamic dispatch.\ntype ISavepoint_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsSavepoint_nameContext differentiates from other interfaces.\n\tIsSavepoint_nameContext()\n}\n\ntype Savepoint_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySavepoint_nameContext() *Savepoint_nameContext {\n\tvar p = new(Savepoint_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_savepoint_name\n\treturn p\n}\n\nfunc InitEmptySavepoint_nameContext(p *Savepoint_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_savepoint_name\n}\n\nfunc (*Savepoint_nameContext) IsSavepoint_nameContext() {}\n\nfunc NewSavepoint_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Savepoint_nameContext {\n\tvar p = new(Savepoint_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_savepoint_name\n\n\treturn p\n}\n\nfunc (s *Savepoint_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Savepoint_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Savepoint_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Savepoint_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Savepoint_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSavepoint_name(s)\n\t}\n}\n\nfunc (s *Savepoint_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSavepoint_name(s)\n\t}\n}\n\nfunc (s *Savepoint_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSavepoint_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Savepoint_name() (localctx ISavepoint_nameContext) {\n\tlocalctx = NewSavepoint_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 204, ParserRULE_savepoint_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2053)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ITable_aliasContext is an interface to support dynamic dispatch.\ntype ITable_aliasContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsTable_aliasContext differentiates from other interfaces.\n\tIsTable_aliasContext()\n}\n\ntype Table_aliasContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyTable_aliasContext() *Table_aliasContext {\n\tvar p = new(Table_aliasContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_alias\n\treturn p\n}\n\nfunc InitEmptyTable_aliasContext(p *Table_aliasContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_alias\n}\n\nfunc (*Table_aliasContext) IsTable_aliasContext() {}\n\nfunc NewTable_aliasContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_aliasContext {\n\tvar p = new(Table_aliasContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_table_alias\n\n\treturn p\n}\n\nfunc (s *Table_aliasContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Table_aliasContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Table_aliasContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Table_aliasContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Table_aliasContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterTable_alias(s)\n\t}\n}\n\nfunc (s *Table_aliasContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitTable_alias(s)\n\t}\n}\n\nfunc (s *Table_aliasContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitTable_alias(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Table_alias() (localctx ITable_aliasContext) {\n\tlocalctx = NewTable_aliasContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 206, ParserRULE_table_alias)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2055)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ITransaction_nameContext is an interface to support dynamic dispatch.\ntype ITransaction_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsTransaction_nameContext differentiates from other interfaces.\n\tIsTransaction_nameContext()\n}\n\ntype Transaction_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyTransaction_nameContext() *Transaction_nameContext {\n\tvar p = new(Transaction_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_transaction_name\n\treturn p\n}\n\nfunc InitEmptyTransaction_nameContext(p *Transaction_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_transaction_name\n}\n\nfunc (*Transaction_nameContext) IsTransaction_nameContext() {}\n\nfunc NewTransaction_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Transaction_nameContext {\n\tvar p = new(Transaction_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_transaction_name\n\n\treturn p\n}\n\nfunc (s *Transaction_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Transaction_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Transaction_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Transaction_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Transaction_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterTransaction_name(s)\n\t}\n}\n\nfunc (s *Transaction_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitTransaction_name(s)\n\t}\n}\n\nfunc (s *Transaction_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitTransaction_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Transaction_name() (localctx ITransaction_nameContext) {\n\tlocalctx = NewTransaction_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 208, ParserRULE_transaction_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2057)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IWindow_nameContext is an interface to support dynamic dispatch.\ntype IWindow_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsWindow_nameContext differentiates from other interfaces.\n\tIsWindow_nameContext()\n}\n\ntype Window_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyWindow_nameContext() *Window_nameContext {\n\tvar p = new(Window_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_window_name\n\treturn p\n}\n\nfunc InitEmptyWindow_nameContext(p *Window_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_window_name\n}\n\nfunc (*Window_nameContext) IsWindow_nameContext() {}\n\nfunc NewWindow_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Window_nameContext {\n\tvar p = new(Window_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_window_name\n\n\treturn p\n}\n\nfunc (s *Window_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Window_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Window_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Window_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Window_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterWindow_name(s)\n\t}\n}\n\nfunc (s *Window_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitWindow_name(s)\n\t}\n}\n\nfunc (s *Window_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitWindow_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Window_name() (localctx IWindow_nameContext) {\n\tlocalctx = NewWindow_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 210, ParserRULE_window_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2059)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IAliasContext is an interface to support dynamic dispatch.\ntype IAliasContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsAliasContext differentiates from other interfaces.\n\tIsAliasContext()\n}\n\ntype AliasContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyAliasContext() *AliasContext {\n\tvar p = new(AliasContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_alias\n\treturn p\n}\n\nfunc InitEmptyAliasContext(p *AliasContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_alias\n}\n\nfunc (*AliasContext) IsAliasContext() {}\n\nfunc NewAliasContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *AliasContext {\n\tvar p = new(AliasContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_alias\n\n\treturn p\n}\n\nfunc (s *AliasContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *AliasContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *AliasContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *AliasContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *AliasContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterAlias(s)\n\t}\n}\n\nfunc (s *AliasContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitAlias(s)\n\t}\n}\n\nfunc (s *AliasContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitAlias(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Alias() (localctx IAliasContext) {\n\tlocalctx = NewAliasContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 212, ParserRULE_alias)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2061)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IFilenameContext is an interface to support dynamic dispatch.\ntype IFilenameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsFilenameContext differentiates from other interfaces.\n\tIsFilenameContext()\n}\n\ntype FilenameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyFilenameContext() *FilenameContext {\n\tvar p = new(FilenameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_filename\n\treturn p\n}\n\nfunc InitEmptyFilenameContext(p *FilenameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_filename\n}\n\nfunc (*FilenameContext) IsFilenameContext() {}\n\nfunc NewFilenameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *FilenameContext {\n\tvar p = new(FilenameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_filename\n\n\treturn p\n}\n\nfunc (s *FilenameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *FilenameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *FilenameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *FilenameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *FilenameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterFilename(s)\n\t}\n}\n\nfunc (s *FilenameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitFilename(s)\n\t}\n}\n\nfunc (s *FilenameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitFilename(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Filename() (localctx IFilenameContext) {\n\tlocalctx = NewFilenameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 214, ParserRULE_filename)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2063)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IBase_window_nameContext is an interface to support dynamic dispatch.\ntype IBase_window_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsBase_window_nameContext differentiates from other interfaces.\n\tIsBase_window_nameContext()\n}\n\ntype Base_window_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyBase_window_nameContext() *Base_window_nameContext {\n\tvar p = new(Base_window_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_base_window_name\n\treturn p\n}\n\nfunc InitEmptyBase_window_nameContext(p *Base_window_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_base_window_name\n}\n\nfunc (*Base_window_nameContext) IsBase_window_nameContext() {}\n\nfunc NewBase_window_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Base_window_nameContext {\n\tvar p = new(Base_window_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_base_window_name\n\n\treturn p\n}\n\nfunc (s *Base_window_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Base_window_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Base_window_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Base_window_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Base_window_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterBase_window_name(s)\n\t}\n}\n\nfunc (s *Base_window_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitBase_window_name(s)\n\t}\n}\n\nfunc (s *Base_window_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitBase_window_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Base_window_name() (localctx IBase_window_nameContext) {\n\tlocalctx = NewBase_window_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 216, ParserRULE_base_window_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2065)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ISimple_funcContext is an interface to support dynamic dispatch.\ntype ISimple_funcContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsSimple_funcContext differentiates from other interfaces.\n\tIsSimple_funcContext()\n}\n\ntype Simple_funcContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptySimple_funcContext() *Simple_funcContext {\n\tvar p = new(Simple_funcContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_simple_func\n\treturn p\n}\n\nfunc InitEmptySimple_funcContext(p *Simple_funcContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_simple_func\n}\n\nfunc (*Simple_funcContext) IsSimple_funcContext() {}\n\nfunc NewSimple_funcContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Simple_funcContext {\n\tvar p = new(Simple_funcContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_simple_func\n\n\treturn p\n}\n\nfunc (s *Simple_funcContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Simple_funcContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Simple_funcContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Simple_funcContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Simple_funcContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterSimple_func(s)\n\t}\n}\n\nfunc (s *Simple_funcContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitSimple_func(s)\n\t}\n}\n\nfunc (s *Simple_funcContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitSimple_func(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Simple_func() (localctx ISimple_funcContext) {\n\tlocalctx = NewSimple_funcContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 218, ParserRULE_simple_func)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2067)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IAggregate_funcContext is an interface to support dynamic dispatch.\ntype IAggregate_funcContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsAggregate_funcContext differentiates from other interfaces.\n\tIsAggregate_funcContext()\n}\n\ntype Aggregate_funcContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyAggregate_funcContext() *Aggregate_funcContext {\n\tvar p = new(Aggregate_funcContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_aggregate_func\n\treturn p\n}\n\nfunc InitEmptyAggregate_funcContext(p *Aggregate_funcContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_aggregate_func\n}\n\nfunc (*Aggregate_funcContext) IsAggregate_funcContext() {}\n\nfunc NewAggregate_funcContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Aggregate_funcContext {\n\tvar p = new(Aggregate_funcContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_aggregate_func\n\n\treturn p\n}\n\nfunc (s *Aggregate_funcContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Aggregate_funcContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Aggregate_funcContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Aggregate_funcContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Aggregate_funcContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterAggregate_func(s)\n\t}\n}\n\nfunc (s *Aggregate_funcContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitAggregate_func(s)\n\t}\n}\n\nfunc (s *Aggregate_funcContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitAggregate_func(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Aggregate_func() (localctx IAggregate_funcContext) {\n\tlocalctx = NewAggregate_funcContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 220, ParserRULE_aggregate_func)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2069)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// ITable_function_nameContext is an interface to support dynamic dispatch.\ntype ITable_function_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tAny_name() IAny_nameContext\n\n\t// IsTable_function_nameContext differentiates from other interfaces.\n\tIsTable_function_nameContext()\n}\n\ntype Table_function_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyTable_function_nameContext() *Table_function_nameContext {\n\tvar p = new(Table_function_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_function_name\n\treturn p\n}\n\nfunc InitEmptyTable_function_nameContext(p *Table_function_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_table_function_name\n}\n\nfunc (*Table_function_nameContext) IsTable_function_nameContext() {}\n\nfunc NewTable_function_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Table_function_nameContext {\n\tvar p = new(Table_function_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_table_function_name\n\n\treturn p\n}\n\nfunc (s *Table_function_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Table_function_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Table_function_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Table_function_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Table_function_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterTable_function_name(s)\n\t}\n}\n\nfunc (s *Table_function_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitTable_function_name(s)\n\t}\n}\n\nfunc (s *Table_function_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitTable_function_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Table_function_name() (localctx ITable_function_nameContext) {\n\tlocalctx = NewTable_function_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 222, ParserRULE_table_function_name)\n\tp.EnterOuterAlt(localctx, 1)\n\t{\n\t\tp.SetState(2071)\n\t\tp.Any_name()\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\n// IAny_nameContext is an interface to support dynamic dispatch.\ntype IAny_nameContext interface {\n\tantlr.ParserRuleContext\n\n\t// GetParser returns the parser.\n\tGetParser() antlr.Parser\n\n\t// Getter signatures\n\tIDENTIFIER() antlr.TerminalNode\n\tKeyword() IKeywordContext\n\tSTRING_LITERAL() antlr.TerminalNode\n\tOPEN_PAR() antlr.TerminalNode\n\tAny_name() IAny_nameContext\n\tCLOSE_PAR() antlr.TerminalNode\n\n\t// IsAny_nameContext differentiates from other interfaces.\n\tIsAny_nameContext()\n}\n\ntype Any_nameContext struct {\n\tantlr.BaseParserRuleContext\n\tparser antlr.Parser\n}\n\nfunc NewEmptyAny_nameContext() *Any_nameContext {\n\tvar p = new(Any_nameContext)\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_any_name\n\treturn p\n}\n\nfunc InitEmptyAny_nameContext(p *Any_nameContext) {\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1)\n\tp.RuleIndex = ParserRULE_any_name\n}\n\nfunc (*Any_nameContext) IsAny_nameContext() {}\n\nfunc NewAny_nameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *Any_nameContext {\n\tvar p = new(Any_nameContext)\n\n\tantlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState)\n\n\tp.parser = parser\n\tp.RuleIndex = ParserRULE_any_name\n\n\treturn p\n}\n\nfunc (s *Any_nameContext) GetParser() antlr.Parser { return s.parser }\n\nfunc (s *Any_nameContext) IDENTIFIER() antlr.TerminalNode {\n\treturn s.GetToken(ParserIDENTIFIER, 0)\n}\n\nfunc (s *Any_nameContext) Keyword() IKeywordContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IKeywordContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IKeywordContext)\n}\n\nfunc (s *Any_nameContext) STRING_LITERAL() antlr.TerminalNode {\n\treturn s.GetToken(ParserSTRING_LITERAL, 0)\n}\n\nfunc (s *Any_nameContext) OPEN_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserOPEN_PAR, 0)\n}\n\nfunc (s *Any_nameContext) Any_name() IAny_nameContext {\n\tvar t antlr.RuleContext\n\tfor _, ctx := range s.GetChildren() {\n\t\tif _, ok := ctx.(IAny_nameContext); ok {\n\t\t\tt = ctx.(antlr.RuleContext)\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif t == nil {\n\t\treturn nil\n\t}\n\n\treturn t.(IAny_nameContext)\n}\n\nfunc (s *Any_nameContext) CLOSE_PAR() antlr.TerminalNode {\n\treturn s.GetToken(ParserCLOSE_PAR, 0)\n}\n\nfunc (s *Any_nameContext) GetRuleContext() antlr.RuleContext {\n\treturn s\n}\n\nfunc (s *Any_nameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {\n\treturn antlr.TreesStringTree(s, ruleNames, recog)\n}\n\nfunc (s *Any_nameContext) EnterRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.EnterAny_name(s)\n\t}\n}\n\nfunc (s *Any_nameContext) ExitRule(listener antlr.ParseTreeListener) {\n\tif listenerT, ok := listener.(ParserListener); ok {\n\t\tlistenerT.ExitAny_name(s)\n\t}\n}\n\nfunc (s *Any_nameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {\n\tswitch t := visitor.(type) {\n\tcase ParserVisitor:\n\t\treturn t.VisitAny_name(s)\n\n\tdefault:\n\t\treturn t.VisitChildren(s)\n\t}\n}\n\nfunc (p *Parser) Any_name() (localctx IAny_nameContext) {\n\tlocalctx = NewAny_nameContext(p, p.GetParserRuleContext(), p.GetState())\n\tp.EnterRule(localctx, 224, ParserRULE_any_name)\n\tp.SetState(2080)\n\tp.GetErrorHandler().Sync(p)\n\tif p.HasError() {\n\t\tgoto errorExit\n\t}\n\n\tswitch p.GetTokenStream().LA(1) {\n\tcase ParserIDENTIFIER:\n\t\tp.EnterOuterAlt(localctx, 1)\n\t\t{\n\t\t\tp.SetState(2073)\n\t\t\tp.Match(ParserIDENTIFIER)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase 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_:\n\t\tp.EnterOuterAlt(localctx, 2)\n\t\t{\n\t\t\tp.SetState(2074)\n\t\t\tp.Keyword()\n\t\t}\n\n\tcase ParserSTRING_LITERAL:\n\t\tp.EnterOuterAlt(localctx, 3)\n\t\t{\n\t\t\tp.SetState(2075)\n\t\t\tp.Match(ParserSTRING_LITERAL)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tcase ParserOPEN_PAR:\n\t\tp.EnterOuterAlt(localctx, 4)\n\t\t{\n\t\t\tp.SetState(2076)\n\t\t\tp.Match(ParserOPEN_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\t\t{\n\t\t\tp.SetState(2077)\n\t\t\tp.Any_name()\n\t\t}\n\t\t{\n\t\t\tp.SetState(2078)\n\t\t\tp.Match(ParserCLOSE_PAR)\n\t\t\tif p.HasError() {\n\t\t\t\t// Recognition error - abort rule\n\t\t\t\tgoto errorExit\n\t\t\t}\n\t\t}\n\n\tdefault:\n\t\tp.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))\n\t\tgoto errorExit\n\t}\n\nerrorExit:\n\tif p.HasError() {\n\t\tv := p.GetError()\n\t\tlocalctx.SetException(v)\n\t\tp.GetErrorHandler().ReportError(p, v)\n\t\tp.GetErrorHandler().Recover(p, v)\n\t\tp.SetError(nil)\n\t}\n\tp.ExitRule()\n\treturn localctx\n\tgoto errorExit // Trick to prevent compiler error if the label is not used\n}\n\nfunc (p *Parser) Sempred(localctx antlr.RuleContext, ruleIndex, predIndex int) bool {\n\tswitch ruleIndex {\n\tcase 32:\n\t\tvar t *ExprContext = nil\n\t\tif localctx != nil {\n\t\t\tt = localctx.(*ExprContext)\n\t\t}\n\t\treturn p.Expr_Sempred(t, predIndex)\n\n\tdefault:\n\t\tpanic(\"No predicate with index: \" + fmt.Sprint(ruleIndex))\n\t}\n}\n\nfunc (p *Parser) Expr_Sempred(localctx antlr.RuleContext, predIndex int) bool {\n\tswitch predIndex {\n\tcase 0:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 20)\n\n\tcase 1:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 19)\n\n\tcase 2:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 18)\n\n\tcase 3:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 17)\n\n\tcase 4:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 16)\n\n\tcase 5:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 15)\n\n\tcase 6:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 14)\n\n\tcase 7:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 13)\n\n\tcase 8:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 6)\n\n\tcase 9:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 5)\n\n\tcase 10:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 9)\n\n\tcase 11:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 8)\n\n\tcase 12:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 7)\n\n\tcase 13:\n\t\treturn p.Precpred(p.GetParserRuleContext(), 4)\n\n\tdefault:\n\t\tpanic(\"No predicate with index: \" + fmt.Sprint(predIndex))\n\t}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqliteparse/parser_base_listener.go",
    "content": "// Code generated from Parser.g4 by ANTLR 4.13.1. DO NOT EDIT.\n\npackage sqliteparse // Parser\nimport \"github.com/antlr4-go/antlr/v4\"\n\n// BaseParserListener is a complete listener for a parse tree produced by Parser.\ntype BaseParserListener struct{}\n\nvar _ ParserListener = &BaseParserListener{}\n\n// VisitTerminal is called when a terminal node is visited.\nfunc (s *BaseParserListener) VisitTerminal(node antlr.TerminalNode) {}\n\n// VisitErrorNode is called when an error node is visited.\nfunc (s *BaseParserListener) VisitErrorNode(node antlr.ErrorNode) {}\n\n// EnterEveryRule is called when any rule is entered.\nfunc (s *BaseParserListener) EnterEveryRule(ctx antlr.ParserRuleContext) {}\n\n// ExitEveryRule is called when any rule is exited.\nfunc (s *BaseParserListener) ExitEveryRule(ctx antlr.ParserRuleContext) {}\n\n// EnterParse is called when production parse is entered.\nfunc (s *BaseParserListener) EnterParse(ctx *ParseContext) {}\n\n// ExitParse is called when production parse is exited.\nfunc (s *BaseParserListener) ExitParse(ctx *ParseContext) {}\n\n// EnterSql_stmt_list is called when production sql_stmt_list is entered.\nfunc (s *BaseParserListener) EnterSql_stmt_list(ctx *Sql_stmt_listContext) {}\n\n// ExitSql_stmt_list is called when production sql_stmt_list is exited.\nfunc (s *BaseParserListener) ExitSql_stmt_list(ctx *Sql_stmt_listContext) {}\n\n// EnterSql_stmt is called when production sql_stmt is entered.\nfunc (s *BaseParserListener) EnterSql_stmt(ctx *Sql_stmtContext) {}\n\n// ExitSql_stmt is called when production sql_stmt is exited.\nfunc (s *BaseParserListener) ExitSql_stmt(ctx *Sql_stmtContext) {}\n\n// EnterAlter_table_stmt is called when production alter_table_stmt is entered.\nfunc (s *BaseParserListener) EnterAlter_table_stmt(ctx *Alter_table_stmtContext) {}\n\n// ExitAlter_table_stmt is called when production alter_table_stmt is exited.\nfunc (s *BaseParserListener) ExitAlter_table_stmt(ctx *Alter_table_stmtContext) {}\n\n// EnterAnalyze_stmt is called when production analyze_stmt is entered.\nfunc (s *BaseParserListener) EnterAnalyze_stmt(ctx *Analyze_stmtContext) {}\n\n// ExitAnalyze_stmt is called when production analyze_stmt is exited.\nfunc (s *BaseParserListener) ExitAnalyze_stmt(ctx *Analyze_stmtContext) {}\n\n// EnterAttach_stmt is called when production attach_stmt is entered.\nfunc (s *BaseParserListener) EnterAttach_stmt(ctx *Attach_stmtContext) {}\n\n// ExitAttach_stmt is called when production attach_stmt is exited.\nfunc (s *BaseParserListener) ExitAttach_stmt(ctx *Attach_stmtContext) {}\n\n// EnterBegin_stmt is called when production begin_stmt is entered.\nfunc (s *BaseParserListener) EnterBegin_stmt(ctx *Begin_stmtContext) {}\n\n// ExitBegin_stmt is called when production begin_stmt is exited.\nfunc (s *BaseParserListener) ExitBegin_stmt(ctx *Begin_stmtContext) {}\n\n// EnterCommit_stmt is called when production commit_stmt is entered.\nfunc (s *BaseParserListener) EnterCommit_stmt(ctx *Commit_stmtContext) {}\n\n// ExitCommit_stmt is called when production commit_stmt is exited.\nfunc (s *BaseParserListener) ExitCommit_stmt(ctx *Commit_stmtContext) {}\n\n// EnterRollback_stmt is called when production rollback_stmt is entered.\nfunc (s *BaseParserListener) EnterRollback_stmt(ctx *Rollback_stmtContext) {}\n\n// ExitRollback_stmt is called when production rollback_stmt is exited.\nfunc (s *BaseParserListener) ExitRollback_stmt(ctx *Rollback_stmtContext) {}\n\n// EnterSavepoint_stmt is called when production savepoint_stmt is entered.\nfunc (s *BaseParserListener) EnterSavepoint_stmt(ctx *Savepoint_stmtContext) {}\n\n// ExitSavepoint_stmt is called when production savepoint_stmt is exited.\nfunc (s *BaseParserListener) ExitSavepoint_stmt(ctx *Savepoint_stmtContext) {}\n\n// EnterRelease_stmt is called when production release_stmt is entered.\nfunc (s *BaseParserListener) EnterRelease_stmt(ctx *Release_stmtContext) {}\n\n// ExitRelease_stmt is called when production release_stmt is exited.\nfunc (s *BaseParserListener) ExitRelease_stmt(ctx *Release_stmtContext) {}\n\n// EnterCreate_index_stmt is called when production create_index_stmt is entered.\nfunc (s *BaseParserListener) EnterCreate_index_stmt(ctx *Create_index_stmtContext) {}\n\n// ExitCreate_index_stmt is called when production create_index_stmt is exited.\nfunc (s *BaseParserListener) ExitCreate_index_stmt(ctx *Create_index_stmtContext) {}\n\n// EnterIndexed_column is called when production indexed_column is entered.\nfunc (s *BaseParserListener) EnterIndexed_column(ctx *Indexed_columnContext) {}\n\n// ExitIndexed_column is called when production indexed_column is exited.\nfunc (s *BaseParserListener) ExitIndexed_column(ctx *Indexed_columnContext) {}\n\n// EnterCreate_table_stmt is called when production create_table_stmt is entered.\nfunc (s *BaseParserListener) EnterCreate_table_stmt(ctx *Create_table_stmtContext) {}\n\n// ExitCreate_table_stmt is called when production create_table_stmt is exited.\nfunc (s *BaseParserListener) ExitCreate_table_stmt(ctx *Create_table_stmtContext) {}\n\n// EnterColumn_def is called when production column_def is entered.\nfunc (s *BaseParserListener) EnterColumn_def(ctx *Column_defContext) {}\n\n// ExitColumn_def is called when production column_def is exited.\nfunc (s *BaseParserListener) ExitColumn_def(ctx *Column_defContext) {}\n\n// EnterType_name is called when production type_name is entered.\nfunc (s *BaseParserListener) EnterType_name(ctx *Type_nameContext) {}\n\n// ExitType_name is called when production type_name is exited.\nfunc (s *BaseParserListener) ExitType_name(ctx *Type_nameContext) {}\n\n// EnterColumn_constraint is called when production column_constraint is entered.\nfunc (s *BaseParserListener) EnterColumn_constraint(ctx *Column_constraintContext) {}\n\n// ExitColumn_constraint is called when production column_constraint is exited.\nfunc (s *BaseParserListener) ExitColumn_constraint(ctx *Column_constraintContext) {}\n\n// EnterSigned_number is called when production signed_number is entered.\nfunc (s *BaseParserListener) EnterSigned_number(ctx *Signed_numberContext) {}\n\n// ExitSigned_number is called when production signed_number is exited.\nfunc (s *BaseParserListener) ExitSigned_number(ctx *Signed_numberContext) {}\n\n// EnterTable_constraint is called when production table_constraint is entered.\nfunc (s *BaseParserListener) EnterTable_constraint(ctx *Table_constraintContext) {}\n\n// ExitTable_constraint is called when production table_constraint is exited.\nfunc (s *BaseParserListener) ExitTable_constraint(ctx *Table_constraintContext) {}\n\n// EnterForeign_key_clause is called when production foreign_key_clause is entered.\nfunc (s *BaseParserListener) EnterForeign_key_clause(ctx *Foreign_key_clauseContext) {}\n\n// ExitForeign_key_clause is called when production foreign_key_clause is exited.\nfunc (s *BaseParserListener) ExitForeign_key_clause(ctx *Foreign_key_clauseContext) {}\n\n// EnterConflict_clause is called when production conflict_clause is entered.\nfunc (s *BaseParserListener) EnterConflict_clause(ctx *Conflict_clauseContext) {}\n\n// ExitConflict_clause is called when production conflict_clause is exited.\nfunc (s *BaseParserListener) ExitConflict_clause(ctx *Conflict_clauseContext) {}\n\n// EnterCreate_trigger_stmt is called when production create_trigger_stmt is entered.\nfunc (s *BaseParserListener) EnterCreate_trigger_stmt(ctx *Create_trigger_stmtContext) {}\n\n// ExitCreate_trigger_stmt is called when production create_trigger_stmt is exited.\nfunc (s *BaseParserListener) ExitCreate_trigger_stmt(ctx *Create_trigger_stmtContext) {}\n\n// EnterCreate_view_stmt is called when production create_view_stmt is entered.\nfunc (s *BaseParserListener) EnterCreate_view_stmt(ctx *Create_view_stmtContext) {}\n\n// ExitCreate_view_stmt is called when production create_view_stmt is exited.\nfunc (s *BaseParserListener) ExitCreate_view_stmt(ctx *Create_view_stmtContext) {}\n\n// EnterCreate_virtual_table_stmt is called when production create_virtual_table_stmt is entered.\nfunc (s *BaseParserListener) EnterCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) {}\n\n// ExitCreate_virtual_table_stmt is called when production create_virtual_table_stmt is exited.\nfunc (s *BaseParserListener) ExitCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) {}\n\n// EnterWith_clause is called when production with_clause is entered.\nfunc (s *BaseParserListener) EnterWith_clause(ctx *With_clauseContext) {}\n\n// ExitWith_clause is called when production with_clause is exited.\nfunc (s *BaseParserListener) ExitWith_clause(ctx *With_clauseContext) {}\n\n// EnterCte_table_name is called when production cte_table_name is entered.\nfunc (s *BaseParserListener) EnterCte_table_name(ctx *Cte_table_nameContext) {}\n\n// ExitCte_table_name is called when production cte_table_name is exited.\nfunc (s *BaseParserListener) ExitCte_table_name(ctx *Cte_table_nameContext) {}\n\n// EnterRecursive_cte is called when production recursive_cte is entered.\nfunc (s *BaseParserListener) EnterRecursive_cte(ctx *Recursive_cteContext) {}\n\n// ExitRecursive_cte is called when production recursive_cte is exited.\nfunc (s *BaseParserListener) ExitRecursive_cte(ctx *Recursive_cteContext) {}\n\n// EnterCommon_table_expression is called when production common_table_expression is entered.\nfunc (s *BaseParserListener) EnterCommon_table_expression(ctx *Common_table_expressionContext) {}\n\n// ExitCommon_table_expression is called when production common_table_expression is exited.\nfunc (s *BaseParserListener) ExitCommon_table_expression(ctx *Common_table_expressionContext) {}\n\n// EnterDelete_stmt is called when production delete_stmt is entered.\nfunc (s *BaseParserListener) EnterDelete_stmt(ctx *Delete_stmtContext) {}\n\n// ExitDelete_stmt is called when production delete_stmt is exited.\nfunc (s *BaseParserListener) ExitDelete_stmt(ctx *Delete_stmtContext) {}\n\n// EnterDelete_stmt_limited is called when production delete_stmt_limited is entered.\nfunc (s *BaseParserListener) EnterDelete_stmt_limited(ctx *Delete_stmt_limitedContext) {}\n\n// ExitDelete_stmt_limited is called when production delete_stmt_limited is exited.\nfunc (s *BaseParserListener) ExitDelete_stmt_limited(ctx *Delete_stmt_limitedContext) {}\n\n// EnterDetach_stmt is called when production detach_stmt is entered.\nfunc (s *BaseParserListener) EnterDetach_stmt(ctx *Detach_stmtContext) {}\n\n// ExitDetach_stmt is called when production detach_stmt is exited.\nfunc (s *BaseParserListener) ExitDetach_stmt(ctx *Detach_stmtContext) {}\n\n// EnterDrop_stmt is called when production drop_stmt is entered.\nfunc (s *BaseParserListener) EnterDrop_stmt(ctx *Drop_stmtContext) {}\n\n// ExitDrop_stmt is called when production drop_stmt is exited.\nfunc (s *BaseParserListener) ExitDrop_stmt(ctx *Drop_stmtContext) {}\n\n// EnterExpr is called when production expr is entered.\nfunc (s *BaseParserListener) EnterExpr(ctx *ExprContext) {}\n\n// ExitExpr is called when production expr is exited.\nfunc (s *BaseParserListener) ExitExpr(ctx *ExprContext) {}\n\n// EnterRaise_function is called when production raise_function is entered.\nfunc (s *BaseParserListener) EnterRaise_function(ctx *Raise_functionContext) {}\n\n// ExitRaise_function is called when production raise_function is exited.\nfunc (s *BaseParserListener) ExitRaise_function(ctx *Raise_functionContext) {}\n\n// EnterLiteral_value is called when production literal_value is entered.\nfunc (s *BaseParserListener) EnterLiteral_value(ctx *Literal_valueContext) {}\n\n// ExitLiteral_value is called when production literal_value is exited.\nfunc (s *BaseParserListener) ExitLiteral_value(ctx *Literal_valueContext) {}\n\n// EnterInsert_stmt is called when production insert_stmt is entered.\nfunc (s *BaseParserListener) EnterInsert_stmt(ctx *Insert_stmtContext) {}\n\n// ExitInsert_stmt is called when production insert_stmt is exited.\nfunc (s *BaseParserListener) ExitInsert_stmt(ctx *Insert_stmtContext) {}\n\n// EnterReturning_clause is called when production returning_clause is entered.\nfunc (s *BaseParserListener) EnterReturning_clause(ctx *Returning_clauseContext) {}\n\n// ExitReturning_clause is called when production returning_clause is exited.\nfunc (s *BaseParserListener) ExitReturning_clause(ctx *Returning_clauseContext) {}\n\n// EnterUpsert_clause is called when production upsert_clause is entered.\nfunc (s *BaseParserListener) EnterUpsert_clause(ctx *Upsert_clauseContext) {}\n\n// ExitUpsert_clause is called when production upsert_clause is exited.\nfunc (s *BaseParserListener) ExitUpsert_clause(ctx *Upsert_clauseContext) {}\n\n// EnterPragma_stmt is called when production pragma_stmt is entered.\nfunc (s *BaseParserListener) EnterPragma_stmt(ctx *Pragma_stmtContext) {}\n\n// ExitPragma_stmt is called when production pragma_stmt is exited.\nfunc (s *BaseParserListener) ExitPragma_stmt(ctx *Pragma_stmtContext) {}\n\n// EnterPragma_value is called when production pragma_value is entered.\nfunc (s *BaseParserListener) EnterPragma_value(ctx *Pragma_valueContext) {}\n\n// ExitPragma_value is called when production pragma_value is exited.\nfunc (s *BaseParserListener) ExitPragma_value(ctx *Pragma_valueContext) {}\n\n// EnterReindex_stmt is called when production reindex_stmt is entered.\nfunc (s *BaseParserListener) EnterReindex_stmt(ctx *Reindex_stmtContext) {}\n\n// ExitReindex_stmt is called when production reindex_stmt is exited.\nfunc (s *BaseParserListener) ExitReindex_stmt(ctx *Reindex_stmtContext) {}\n\n// EnterSelect_stmt is called when production select_stmt is entered.\nfunc (s *BaseParserListener) EnterSelect_stmt(ctx *Select_stmtContext) {}\n\n// ExitSelect_stmt is called when production select_stmt is exited.\nfunc (s *BaseParserListener) ExitSelect_stmt(ctx *Select_stmtContext) {}\n\n// EnterJoin_clause is called when production join_clause is entered.\nfunc (s *BaseParserListener) EnterJoin_clause(ctx *Join_clauseContext) {}\n\n// ExitJoin_clause is called when production join_clause is exited.\nfunc (s *BaseParserListener) ExitJoin_clause(ctx *Join_clauseContext) {}\n\n// EnterSelect_core is called when production select_core is entered.\nfunc (s *BaseParserListener) EnterSelect_core(ctx *Select_coreContext) {}\n\n// ExitSelect_core is called when production select_core is exited.\nfunc (s *BaseParserListener) ExitSelect_core(ctx *Select_coreContext) {}\n\n// EnterFactored_select_stmt is called when production factored_select_stmt is entered.\nfunc (s *BaseParserListener) EnterFactored_select_stmt(ctx *Factored_select_stmtContext) {}\n\n// ExitFactored_select_stmt is called when production factored_select_stmt is exited.\nfunc (s *BaseParserListener) ExitFactored_select_stmt(ctx *Factored_select_stmtContext) {}\n\n// EnterSimple_select_stmt is called when production simple_select_stmt is entered.\nfunc (s *BaseParserListener) EnterSimple_select_stmt(ctx *Simple_select_stmtContext) {}\n\n// ExitSimple_select_stmt is called when production simple_select_stmt is exited.\nfunc (s *BaseParserListener) ExitSimple_select_stmt(ctx *Simple_select_stmtContext) {}\n\n// EnterCompound_select_stmt is called when production compound_select_stmt is entered.\nfunc (s *BaseParserListener) EnterCompound_select_stmt(ctx *Compound_select_stmtContext) {}\n\n// ExitCompound_select_stmt is called when production compound_select_stmt is exited.\nfunc (s *BaseParserListener) ExitCompound_select_stmt(ctx *Compound_select_stmtContext) {}\n\n// EnterTable_or_subquery is called when production table_or_subquery is entered.\nfunc (s *BaseParserListener) EnterTable_or_subquery(ctx *Table_or_subqueryContext) {}\n\n// ExitTable_or_subquery is called when production table_or_subquery is exited.\nfunc (s *BaseParserListener) ExitTable_or_subquery(ctx *Table_or_subqueryContext) {}\n\n// EnterResult_column is called when production result_column is entered.\nfunc (s *BaseParserListener) EnterResult_column(ctx *Result_columnContext) {}\n\n// ExitResult_column is called when production result_column is exited.\nfunc (s *BaseParserListener) ExitResult_column(ctx *Result_columnContext) {}\n\n// EnterJoin_operator is called when production join_operator is entered.\nfunc (s *BaseParserListener) EnterJoin_operator(ctx *Join_operatorContext) {}\n\n// ExitJoin_operator is called when production join_operator is exited.\nfunc (s *BaseParserListener) ExitJoin_operator(ctx *Join_operatorContext) {}\n\n// EnterJoin_constraint is called when production join_constraint is entered.\nfunc (s *BaseParserListener) EnterJoin_constraint(ctx *Join_constraintContext) {}\n\n// ExitJoin_constraint is called when production join_constraint is exited.\nfunc (s *BaseParserListener) ExitJoin_constraint(ctx *Join_constraintContext) {}\n\n// EnterCompound_operator is called when production compound_operator is entered.\nfunc (s *BaseParserListener) EnterCompound_operator(ctx *Compound_operatorContext) {}\n\n// ExitCompound_operator is called when production compound_operator is exited.\nfunc (s *BaseParserListener) ExitCompound_operator(ctx *Compound_operatorContext) {}\n\n// EnterUpdate_stmt is called when production update_stmt is entered.\nfunc (s *BaseParserListener) EnterUpdate_stmt(ctx *Update_stmtContext) {}\n\n// ExitUpdate_stmt is called when production update_stmt is exited.\nfunc (s *BaseParserListener) ExitUpdate_stmt(ctx *Update_stmtContext) {}\n\n// EnterAssignment_list is called when production assignment_list is entered.\nfunc (s *BaseParserListener) EnterAssignment_list(ctx *Assignment_listContext) {}\n\n// ExitAssignment_list is called when production assignment_list is exited.\nfunc (s *BaseParserListener) ExitAssignment_list(ctx *Assignment_listContext) {}\n\n// EnterAssignment is called when production assignment is entered.\nfunc (s *BaseParserListener) EnterAssignment(ctx *AssignmentContext) {}\n\n// ExitAssignment is called when production assignment is exited.\nfunc (s *BaseParserListener) ExitAssignment(ctx *AssignmentContext) {}\n\n// EnterColumn_name_list is called when production column_name_list is entered.\nfunc (s *BaseParserListener) EnterColumn_name_list(ctx *Column_name_listContext) {}\n\n// ExitColumn_name_list is called when production column_name_list is exited.\nfunc (s *BaseParserListener) ExitColumn_name_list(ctx *Column_name_listContext) {}\n\n// EnterUpdate_stmt_limited is called when production update_stmt_limited is entered.\nfunc (s *BaseParserListener) EnterUpdate_stmt_limited(ctx *Update_stmt_limitedContext) {}\n\n// ExitUpdate_stmt_limited is called when production update_stmt_limited is exited.\nfunc (s *BaseParserListener) ExitUpdate_stmt_limited(ctx *Update_stmt_limitedContext) {}\n\n// EnterQualified_table_name is called when production qualified_table_name is entered.\nfunc (s *BaseParserListener) EnterQualified_table_name(ctx *Qualified_table_nameContext) {}\n\n// ExitQualified_table_name is called when production qualified_table_name is exited.\nfunc (s *BaseParserListener) ExitQualified_table_name(ctx *Qualified_table_nameContext) {}\n\n// EnterVacuum_stmt is called when production vacuum_stmt is entered.\nfunc (s *BaseParserListener) EnterVacuum_stmt(ctx *Vacuum_stmtContext) {}\n\n// ExitVacuum_stmt is called when production vacuum_stmt is exited.\nfunc (s *BaseParserListener) ExitVacuum_stmt(ctx *Vacuum_stmtContext) {}\n\n// EnterFilter_clause is called when production filter_clause is entered.\nfunc (s *BaseParserListener) EnterFilter_clause(ctx *Filter_clauseContext) {}\n\n// ExitFilter_clause is called when production filter_clause is exited.\nfunc (s *BaseParserListener) ExitFilter_clause(ctx *Filter_clauseContext) {}\n\n// EnterWindow_defn is called when production window_defn is entered.\nfunc (s *BaseParserListener) EnterWindow_defn(ctx *Window_defnContext) {}\n\n// ExitWindow_defn is called when production window_defn is exited.\nfunc (s *BaseParserListener) ExitWindow_defn(ctx *Window_defnContext) {}\n\n// EnterOver_clause is called when production over_clause is entered.\nfunc (s *BaseParserListener) EnterOver_clause(ctx *Over_clauseContext) {}\n\n// ExitOver_clause is called when production over_clause is exited.\nfunc (s *BaseParserListener) ExitOver_clause(ctx *Over_clauseContext) {}\n\n// EnterFrame_spec is called when production frame_spec is entered.\nfunc (s *BaseParserListener) EnterFrame_spec(ctx *Frame_specContext) {}\n\n// ExitFrame_spec is called when production frame_spec is exited.\nfunc (s *BaseParserListener) ExitFrame_spec(ctx *Frame_specContext) {}\n\n// EnterFrame_clause is called when production frame_clause is entered.\nfunc (s *BaseParserListener) EnterFrame_clause(ctx *Frame_clauseContext) {}\n\n// ExitFrame_clause is called when production frame_clause is exited.\nfunc (s *BaseParserListener) ExitFrame_clause(ctx *Frame_clauseContext) {}\n\n// EnterSimple_function_invocation is called when production simple_function_invocation is entered.\nfunc (s *BaseParserListener) EnterSimple_function_invocation(ctx *Simple_function_invocationContext) {\n}\n\n// ExitSimple_function_invocation is called when production simple_function_invocation is exited.\nfunc (s *BaseParserListener) ExitSimple_function_invocation(ctx *Simple_function_invocationContext) {}\n\n// EnterAggregate_function_invocation is called when production aggregate_function_invocation is entered.\nfunc (s *BaseParserListener) EnterAggregate_function_invocation(ctx *Aggregate_function_invocationContext) {\n}\n\n// ExitAggregate_function_invocation is called when production aggregate_function_invocation is exited.\nfunc (s *BaseParserListener) ExitAggregate_function_invocation(ctx *Aggregate_function_invocationContext) {\n}\n\n// EnterWindow_function_invocation is called when production window_function_invocation is entered.\nfunc (s *BaseParserListener) EnterWindow_function_invocation(ctx *Window_function_invocationContext) {\n}\n\n// ExitWindow_function_invocation is called when production window_function_invocation is exited.\nfunc (s *BaseParserListener) ExitWindow_function_invocation(ctx *Window_function_invocationContext) {}\n\n// EnterCommon_table_stmt is called when production common_table_stmt is entered.\nfunc (s *BaseParserListener) EnterCommon_table_stmt(ctx *Common_table_stmtContext) {}\n\n// ExitCommon_table_stmt is called when production common_table_stmt is exited.\nfunc (s *BaseParserListener) ExitCommon_table_stmt(ctx *Common_table_stmtContext) {}\n\n// EnterOrder_by_stmt is called when production order_by_stmt is entered.\nfunc (s *BaseParserListener) EnterOrder_by_stmt(ctx *Order_by_stmtContext) {}\n\n// ExitOrder_by_stmt is called when production order_by_stmt is exited.\nfunc (s *BaseParserListener) ExitOrder_by_stmt(ctx *Order_by_stmtContext) {}\n\n// EnterLimit_stmt is called when production limit_stmt is entered.\nfunc (s *BaseParserListener) EnterLimit_stmt(ctx *Limit_stmtContext) {}\n\n// ExitLimit_stmt is called when production limit_stmt is exited.\nfunc (s *BaseParserListener) ExitLimit_stmt(ctx *Limit_stmtContext) {}\n\n// EnterOrdering_term is called when production ordering_term is entered.\nfunc (s *BaseParserListener) EnterOrdering_term(ctx *Ordering_termContext) {}\n\n// ExitOrdering_term is called when production ordering_term is exited.\nfunc (s *BaseParserListener) ExitOrdering_term(ctx *Ordering_termContext) {}\n\n// EnterAsc_desc is called when production asc_desc is entered.\nfunc (s *BaseParserListener) EnterAsc_desc(ctx *Asc_descContext) {}\n\n// ExitAsc_desc is called when production asc_desc is exited.\nfunc (s *BaseParserListener) ExitAsc_desc(ctx *Asc_descContext) {}\n\n// EnterFrame_left is called when production frame_left is entered.\nfunc (s *BaseParserListener) EnterFrame_left(ctx *Frame_leftContext) {}\n\n// ExitFrame_left is called when production frame_left is exited.\nfunc (s *BaseParserListener) ExitFrame_left(ctx *Frame_leftContext) {}\n\n// EnterFrame_right is called when production frame_right is entered.\nfunc (s *BaseParserListener) EnterFrame_right(ctx *Frame_rightContext) {}\n\n// ExitFrame_right is called when production frame_right is exited.\nfunc (s *BaseParserListener) ExitFrame_right(ctx *Frame_rightContext) {}\n\n// EnterFrame_single is called when production frame_single is entered.\nfunc (s *BaseParserListener) EnterFrame_single(ctx *Frame_singleContext) {}\n\n// ExitFrame_single is called when production frame_single is exited.\nfunc (s *BaseParserListener) ExitFrame_single(ctx *Frame_singleContext) {}\n\n// EnterWindow_function is called when production window_function is entered.\nfunc (s *BaseParserListener) EnterWindow_function(ctx *Window_functionContext) {}\n\n// ExitWindow_function is called when production window_function is exited.\nfunc (s *BaseParserListener) ExitWindow_function(ctx *Window_functionContext) {}\n\n// EnterOffset is called when production offset is entered.\nfunc (s *BaseParserListener) EnterOffset(ctx *OffsetContext) {}\n\n// ExitOffset is called when production offset is exited.\nfunc (s *BaseParserListener) ExitOffset(ctx *OffsetContext) {}\n\n// EnterDefault_value is called when production default_value is entered.\nfunc (s *BaseParserListener) EnterDefault_value(ctx *Default_valueContext) {}\n\n// ExitDefault_value is called when production default_value is exited.\nfunc (s *BaseParserListener) ExitDefault_value(ctx *Default_valueContext) {}\n\n// EnterPartition_by is called when production partition_by is entered.\nfunc (s *BaseParserListener) EnterPartition_by(ctx *Partition_byContext) {}\n\n// ExitPartition_by is called when production partition_by is exited.\nfunc (s *BaseParserListener) ExitPartition_by(ctx *Partition_byContext) {}\n\n// EnterOrder_by_expr is called when production order_by_expr is entered.\nfunc (s *BaseParserListener) EnterOrder_by_expr(ctx *Order_by_exprContext) {}\n\n// ExitOrder_by_expr is called when production order_by_expr is exited.\nfunc (s *BaseParserListener) ExitOrder_by_expr(ctx *Order_by_exprContext) {}\n\n// EnterOrder_by_expr_asc_desc is called when production order_by_expr_asc_desc is entered.\nfunc (s *BaseParserListener) EnterOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) {}\n\n// ExitOrder_by_expr_asc_desc is called when production order_by_expr_asc_desc is exited.\nfunc (s *BaseParserListener) ExitOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) {}\n\n// EnterExpr_asc_desc is called when production expr_asc_desc is entered.\nfunc (s *BaseParserListener) EnterExpr_asc_desc(ctx *Expr_asc_descContext) {}\n\n// ExitExpr_asc_desc is called when production expr_asc_desc is exited.\nfunc (s *BaseParserListener) ExitExpr_asc_desc(ctx *Expr_asc_descContext) {}\n\n// EnterInitial_select is called when production initial_select is entered.\nfunc (s *BaseParserListener) EnterInitial_select(ctx *Initial_selectContext) {}\n\n// ExitInitial_select is called when production initial_select is exited.\nfunc (s *BaseParserListener) ExitInitial_select(ctx *Initial_selectContext) {}\n\n// EnterRecursive_select is called when production recursive_select is entered.\nfunc (s *BaseParserListener) EnterRecursive_select(ctx *Recursive_selectContext) {}\n\n// ExitRecursive_select is called when production recursive_select is exited.\nfunc (s *BaseParserListener) ExitRecursive_select(ctx *Recursive_selectContext) {}\n\n// EnterUnary_operator is called when production unary_operator is entered.\nfunc (s *BaseParserListener) EnterUnary_operator(ctx *Unary_operatorContext) {}\n\n// ExitUnary_operator is called when production unary_operator is exited.\nfunc (s *BaseParserListener) ExitUnary_operator(ctx *Unary_operatorContext) {}\n\n// EnterError_message is called when production error_message is entered.\nfunc (s *BaseParserListener) EnterError_message(ctx *Error_messageContext) {}\n\n// ExitError_message is called when production error_message is exited.\nfunc (s *BaseParserListener) ExitError_message(ctx *Error_messageContext) {}\n\n// EnterModule_argument is called when production module_argument is entered.\nfunc (s *BaseParserListener) EnterModule_argument(ctx *Module_argumentContext) {}\n\n// ExitModule_argument is called when production module_argument is exited.\nfunc (s *BaseParserListener) ExitModule_argument(ctx *Module_argumentContext) {}\n\n// EnterColumn_alias is called when production column_alias is entered.\nfunc (s *BaseParserListener) EnterColumn_alias(ctx *Column_aliasContext) {}\n\n// ExitColumn_alias is called when production column_alias is exited.\nfunc (s *BaseParserListener) ExitColumn_alias(ctx *Column_aliasContext) {}\n\n// EnterKeyword is called when production keyword is entered.\nfunc (s *BaseParserListener) EnterKeyword(ctx *KeywordContext) {}\n\n// ExitKeyword is called when production keyword is exited.\nfunc (s *BaseParserListener) ExitKeyword(ctx *KeywordContext) {}\n\n// EnterName is called when production name is entered.\nfunc (s *BaseParserListener) EnterName(ctx *NameContext) {}\n\n// ExitName is called when production name is exited.\nfunc (s *BaseParserListener) ExitName(ctx *NameContext) {}\n\n// EnterFunction_name is called when production function_name is entered.\nfunc (s *BaseParserListener) EnterFunction_name(ctx *Function_nameContext) {}\n\n// ExitFunction_name is called when production function_name is exited.\nfunc (s *BaseParserListener) ExitFunction_name(ctx *Function_nameContext) {}\n\n// EnterSchema_name is called when production schema_name is entered.\nfunc (s *BaseParserListener) EnterSchema_name(ctx *Schema_nameContext) {}\n\n// ExitSchema_name is called when production schema_name is exited.\nfunc (s *BaseParserListener) ExitSchema_name(ctx *Schema_nameContext) {}\n\n// EnterTable_name is called when production table_name is entered.\nfunc (s *BaseParserListener) EnterTable_name(ctx *Table_nameContext) {}\n\n// ExitTable_name is called when production table_name is exited.\nfunc (s *BaseParserListener) ExitTable_name(ctx *Table_nameContext) {}\n\n// EnterTable_or_index_name is called when production table_or_index_name is entered.\nfunc (s *BaseParserListener) EnterTable_or_index_name(ctx *Table_or_index_nameContext) {}\n\n// ExitTable_or_index_name is called when production table_or_index_name is exited.\nfunc (s *BaseParserListener) ExitTable_or_index_name(ctx *Table_or_index_nameContext) {}\n\n// EnterColumn_name is called when production column_name is entered.\nfunc (s *BaseParserListener) EnterColumn_name(ctx *Column_nameContext) {}\n\n// ExitColumn_name is called when production column_name is exited.\nfunc (s *BaseParserListener) ExitColumn_name(ctx *Column_nameContext) {}\n\n// EnterCollation_name is called when production collation_name is entered.\nfunc (s *BaseParserListener) EnterCollation_name(ctx *Collation_nameContext) {}\n\n// ExitCollation_name is called when production collation_name is exited.\nfunc (s *BaseParserListener) ExitCollation_name(ctx *Collation_nameContext) {}\n\n// EnterForeign_table is called when production foreign_table is entered.\nfunc (s *BaseParserListener) EnterForeign_table(ctx *Foreign_tableContext) {}\n\n// ExitForeign_table is called when production foreign_table is exited.\nfunc (s *BaseParserListener) ExitForeign_table(ctx *Foreign_tableContext) {}\n\n// EnterIndex_name is called when production index_name is entered.\nfunc (s *BaseParserListener) EnterIndex_name(ctx *Index_nameContext) {}\n\n// ExitIndex_name is called when production index_name is exited.\nfunc (s *BaseParserListener) ExitIndex_name(ctx *Index_nameContext) {}\n\n// EnterTrigger_name is called when production trigger_name is entered.\nfunc (s *BaseParserListener) EnterTrigger_name(ctx *Trigger_nameContext) {}\n\n// ExitTrigger_name is called when production trigger_name is exited.\nfunc (s *BaseParserListener) ExitTrigger_name(ctx *Trigger_nameContext) {}\n\n// EnterView_name is called when production view_name is entered.\nfunc (s *BaseParserListener) EnterView_name(ctx *View_nameContext) {}\n\n// ExitView_name is called when production view_name is exited.\nfunc (s *BaseParserListener) ExitView_name(ctx *View_nameContext) {}\n\n// EnterModule_name is called when production module_name is entered.\nfunc (s *BaseParserListener) EnterModule_name(ctx *Module_nameContext) {}\n\n// ExitModule_name is called when production module_name is exited.\nfunc (s *BaseParserListener) ExitModule_name(ctx *Module_nameContext) {}\n\n// EnterPragma_name is called when production pragma_name is entered.\nfunc (s *BaseParserListener) EnterPragma_name(ctx *Pragma_nameContext) {}\n\n// ExitPragma_name is called when production pragma_name is exited.\nfunc (s *BaseParserListener) ExitPragma_name(ctx *Pragma_nameContext) {}\n\n// EnterSavepoint_name is called when production savepoint_name is entered.\nfunc (s *BaseParserListener) EnterSavepoint_name(ctx *Savepoint_nameContext) {}\n\n// ExitSavepoint_name is called when production savepoint_name is exited.\nfunc (s *BaseParserListener) ExitSavepoint_name(ctx *Savepoint_nameContext) {}\n\n// EnterTable_alias is called when production table_alias is entered.\nfunc (s *BaseParserListener) EnterTable_alias(ctx *Table_aliasContext) {}\n\n// ExitTable_alias is called when production table_alias is exited.\nfunc (s *BaseParserListener) ExitTable_alias(ctx *Table_aliasContext) {}\n\n// EnterTransaction_name is called when production transaction_name is entered.\nfunc (s *BaseParserListener) EnterTransaction_name(ctx *Transaction_nameContext) {}\n\n// ExitTransaction_name is called when production transaction_name is exited.\nfunc (s *BaseParserListener) ExitTransaction_name(ctx *Transaction_nameContext) {}\n\n// EnterWindow_name is called when production window_name is entered.\nfunc (s *BaseParserListener) EnterWindow_name(ctx *Window_nameContext) {}\n\n// ExitWindow_name is called when production window_name is exited.\nfunc (s *BaseParserListener) ExitWindow_name(ctx *Window_nameContext) {}\n\n// EnterAlias is called when production alias is entered.\nfunc (s *BaseParserListener) EnterAlias(ctx *AliasContext) {}\n\n// ExitAlias is called when production alias is exited.\nfunc (s *BaseParserListener) ExitAlias(ctx *AliasContext) {}\n\n// EnterFilename is called when production filename is entered.\nfunc (s *BaseParserListener) EnterFilename(ctx *FilenameContext) {}\n\n// ExitFilename is called when production filename is exited.\nfunc (s *BaseParserListener) ExitFilename(ctx *FilenameContext) {}\n\n// EnterBase_window_name is called when production base_window_name is entered.\nfunc (s *BaseParserListener) EnterBase_window_name(ctx *Base_window_nameContext) {}\n\n// ExitBase_window_name is called when production base_window_name is exited.\nfunc (s *BaseParserListener) ExitBase_window_name(ctx *Base_window_nameContext) {}\n\n// EnterSimple_func is called when production simple_func is entered.\nfunc (s *BaseParserListener) EnterSimple_func(ctx *Simple_funcContext) {}\n\n// ExitSimple_func is called when production simple_func is exited.\nfunc (s *BaseParserListener) ExitSimple_func(ctx *Simple_funcContext) {}\n\n// EnterAggregate_func is called when production aggregate_func is entered.\nfunc (s *BaseParserListener) EnterAggregate_func(ctx *Aggregate_funcContext) {}\n\n// ExitAggregate_func is called when production aggregate_func is exited.\nfunc (s *BaseParserListener) ExitAggregate_func(ctx *Aggregate_funcContext) {}\n\n// EnterTable_function_name is called when production table_function_name is entered.\nfunc (s *BaseParserListener) EnterTable_function_name(ctx *Table_function_nameContext) {}\n\n// ExitTable_function_name is called when production table_function_name is exited.\nfunc (s *BaseParserListener) ExitTable_function_name(ctx *Table_function_nameContext) {}\n\n// EnterAny_name is called when production any_name is entered.\nfunc (s *BaseParserListener) EnterAny_name(ctx *Any_nameContext) {}\n\n// ExitAny_name is called when production any_name is exited.\nfunc (s *BaseParserListener) ExitAny_name(ctx *Any_nameContext) {}\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqliteparse/parser_base_visitor.go",
    "content": "// Code generated from Parser.g4 by ANTLR 4.13.1. DO NOT EDIT.\n\npackage sqliteparse // Parser\nimport \"github.com/antlr4-go/antlr/v4\"\n\ntype BaseParserVisitor struct {\n\t*antlr.BaseParseTreeVisitor\n}\n\nfunc (v *BaseParserVisitor) VisitParse(ctx *ParseContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSql_stmt_list(ctx *Sql_stmt_listContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSql_stmt(ctx *Sql_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitAlter_table_stmt(ctx *Alter_table_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitAnalyze_stmt(ctx *Analyze_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitAttach_stmt(ctx *Attach_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitBegin_stmt(ctx *Begin_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCommit_stmt(ctx *Commit_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitRollback_stmt(ctx *Rollback_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSavepoint_stmt(ctx *Savepoint_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitRelease_stmt(ctx *Release_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCreate_index_stmt(ctx *Create_index_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitIndexed_column(ctx *Indexed_columnContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCreate_table_stmt(ctx *Create_table_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitColumn_def(ctx *Column_defContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitType_name(ctx *Type_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitColumn_constraint(ctx *Column_constraintContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSigned_number(ctx *Signed_numberContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitTable_constraint(ctx *Table_constraintContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitForeign_key_clause(ctx *Foreign_key_clauseContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitConflict_clause(ctx *Conflict_clauseContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCreate_trigger_stmt(ctx *Create_trigger_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCreate_view_stmt(ctx *Create_view_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitWith_clause(ctx *With_clauseContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCte_table_name(ctx *Cte_table_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitRecursive_cte(ctx *Recursive_cteContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCommon_table_expression(ctx *Common_table_expressionContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitDelete_stmt(ctx *Delete_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitDelete_stmt_limited(ctx *Delete_stmt_limitedContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitDetach_stmt(ctx *Detach_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitDrop_stmt(ctx *Drop_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitExpr(ctx *ExprContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitRaise_function(ctx *Raise_functionContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitLiteral_value(ctx *Literal_valueContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitInsert_stmt(ctx *Insert_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitReturning_clause(ctx *Returning_clauseContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitUpsert_clause(ctx *Upsert_clauseContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitPragma_stmt(ctx *Pragma_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitPragma_value(ctx *Pragma_valueContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitReindex_stmt(ctx *Reindex_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSelect_stmt(ctx *Select_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitJoin_clause(ctx *Join_clauseContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSelect_core(ctx *Select_coreContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitFactored_select_stmt(ctx *Factored_select_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSimple_select_stmt(ctx *Simple_select_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCompound_select_stmt(ctx *Compound_select_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitTable_or_subquery(ctx *Table_or_subqueryContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitResult_column(ctx *Result_columnContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitJoin_operator(ctx *Join_operatorContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitJoin_constraint(ctx *Join_constraintContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCompound_operator(ctx *Compound_operatorContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitUpdate_stmt(ctx *Update_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitAssignment_list(ctx *Assignment_listContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitAssignment(ctx *AssignmentContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitColumn_name_list(ctx *Column_name_listContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitUpdate_stmt_limited(ctx *Update_stmt_limitedContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitQualified_table_name(ctx *Qualified_table_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitVacuum_stmt(ctx *Vacuum_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitFilter_clause(ctx *Filter_clauseContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitWindow_defn(ctx *Window_defnContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitOver_clause(ctx *Over_clauseContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitFrame_spec(ctx *Frame_specContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitFrame_clause(ctx *Frame_clauseContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSimple_function_invocation(ctx *Simple_function_invocationContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitAggregate_function_invocation(ctx *Aggregate_function_invocationContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitWindow_function_invocation(ctx *Window_function_invocationContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCommon_table_stmt(ctx *Common_table_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitOrder_by_stmt(ctx *Order_by_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitLimit_stmt(ctx *Limit_stmtContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitOrdering_term(ctx *Ordering_termContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitAsc_desc(ctx *Asc_descContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitFrame_left(ctx *Frame_leftContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitFrame_right(ctx *Frame_rightContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitFrame_single(ctx *Frame_singleContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitWindow_function(ctx *Window_functionContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitOffset(ctx *OffsetContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitDefault_value(ctx *Default_valueContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitPartition_by(ctx *Partition_byContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitOrder_by_expr(ctx *Order_by_exprContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitExpr_asc_desc(ctx *Expr_asc_descContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitInitial_select(ctx *Initial_selectContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitRecursive_select(ctx *Recursive_selectContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitUnary_operator(ctx *Unary_operatorContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitError_message(ctx *Error_messageContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitModule_argument(ctx *Module_argumentContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitColumn_alias(ctx *Column_aliasContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitKeyword(ctx *KeywordContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitName(ctx *NameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitFunction_name(ctx *Function_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSchema_name(ctx *Schema_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitTable_name(ctx *Table_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitTable_or_index_name(ctx *Table_or_index_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitColumn_name(ctx *Column_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitCollation_name(ctx *Collation_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitForeign_table(ctx *Foreign_tableContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitIndex_name(ctx *Index_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitTrigger_name(ctx *Trigger_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitView_name(ctx *View_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitModule_name(ctx *Module_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitPragma_name(ctx *Pragma_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSavepoint_name(ctx *Savepoint_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitTable_alias(ctx *Table_aliasContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitTransaction_name(ctx *Transaction_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitWindow_name(ctx *Window_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitAlias(ctx *AliasContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitFilename(ctx *FilenameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitBase_window_name(ctx *Base_window_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitSimple_func(ctx *Simple_funcContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitAggregate_func(ctx *Aggregate_funcContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitTable_function_name(ctx *Table_function_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n\nfunc (v *BaseParserVisitor) VisitAny_name(ctx *Any_nameContext) interface{} {\n\treturn v.VisitChildren(ctx)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqliteparse/parser_listener.go",
    "content": "// Code generated from Parser.g4 by ANTLR 4.13.1. DO NOT EDIT.\n\npackage sqliteparse // Parser\nimport \"github.com/antlr4-go/antlr/v4\"\n\n// ParserListener is a complete listener for a parse tree produced by Parser.\ntype ParserListener interface {\n\tantlr.ParseTreeListener\n\n\t// EnterParse is called when entering the parse production.\n\tEnterParse(c *ParseContext)\n\n\t// EnterSql_stmt_list is called when entering the sql_stmt_list production.\n\tEnterSql_stmt_list(c *Sql_stmt_listContext)\n\n\t// EnterSql_stmt is called when entering the sql_stmt production.\n\tEnterSql_stmt(c *Sql_stmtContext)\n\n\t// EnterAlter_table_stmt is called when entering the alter_table_stmt production.\n\tEnterAlter_table_stmt(c *Alter_table_stmtContext)\n\n\t// EnterAnalyze_stmt is called when entering the analyze_stmt production.\n\tEnterAnalyze_stmt(c *Analyze_stmtContext)\n\n\t// EnterAttach_stmt is called when entering the attach_stmt production.\n\tEnterAttach_stmt(c *Attach_stmtContext)\n\n\t// EnterBegin_stmt is called when entering the begin_stmt production.\n\tEnterBegin_stmt(c *Begin_stmtContext)\n\n\t// EnterCommit_stmt is called when entering the commit_stmt production.\n\tEnterCommit_stmt(c *Commit_stmtContext)\n\n\t// EnterRollback_stmt is called when entering the rollback_stmt production.\n\tEnterRollback_stmt(c *Rollback_stmtContext)\n\n\t// EnterSavepoint_stmt is called when entering the savepoint_stmt production.\n\tEnterSavepoint_stmt(c *Savepoint_stmtContext)\n\n\t// EnterRelease_stmt is called when entering the release_stmt production.\n\tEnterRelease_stmt(c *Release_stmtContext)\n\n\t// EnterCreate_index_stmt is called when entering the create_index_stmt production.\n\tEnterCreate_index_stmt(c *Create_index_stmtContext)\n\n\t// EnterIndexed_column is called when entering the indexed_column production.\n\tEnterIndexed_column(c *Indexed_columnContext)\n\n\t// EnterCreate_table_stmt is called when entering the create_table_stmt production.\n\tEnterCreate_table_stmt(c *Create_table_stmtContext)\n\n\t// EnterColumn_def is called when entering the column_def production.\n\tEnterColumn_def(c *Column_defContext)\n\n\t// EnterType_name is called when entering the type_name production.\n\tEnterType_name(c *Type_nameContext)\n\n\t// EnterColumn_constraint is called when entering the column_constraint production.\n\tEnterColumn_constraint(c *Column_constraintContext)\n\n\t// EnterSigned_number is called when entering the signed_number production.\n\tEnterSigned_number(c *Signed_numberContext)\n\n\t// EnterTable_constraint is called when entering the table_constraint production.\n\tEnterTable_constraint(c *Table_constraintContext)\n\n\t// EnterForeign_key_clause is called when entering the foreign_key_clause production.\n\tEnterForeign_key_clause(c *Foreign_key_clauseContext)\n\n\t// EnterConflict_clause is called when entering the conflict_clause production.\n\tEnterConflict_clause(c *Conflict_clauseContext)\n\n\t// EnterCreate_trigger_stmt is called when entering the create_trigger_stmt production.\n\tEnterCreate_trigger_stmt(c *Create_trigger_stmtContext)\n\n\t// EnterCreate_view_stmt is called when entering the create_view_stmt production.\n\tEnterCreate_view_stmt(c *Create_view_stmtContext)\n\n\t// EnterCreate_virtual_table_stmt is called when entering the create_virtual_table_stmt production.\n\tEnterCreate_virtual_table_stmt(c *Create_virtual_table_stmtContext)\n\n\t// EnterWith_clause is called when entering the with_clause production.\n\tEnterWith_clause(c *With_clauseContext)\n\n\t// EnterCte_table_name is called when entering the cte_table_name production.\n\tEnterCte_table_name(c *Cte_table_nameContext)\n\n\t// EnterRecursive_cte is called when entering the recursive_cte production.\n\tEnterRecursive_cte(c *Recursive_cteContext)\n\n\t// EnterCommon_table_expression is called when entering the common_table_expression production.\n\tEnterCommon_table_expression(c *Common_table_expressionContext)\n\n\t// EnterDelete_stmt is called when entering the delete_stmt production.\n\tEnterDelete_stmt(c *Delete_stmtContext)\n\n\t// EnterDelete_stmt_limited is called when entering the delete_stmt_limited production.\n\tEnterDelete_stmt_limited(c *Delete_stmt_limitedContext)\n\n\t// EnterDetach_stmt is called when entering the detach_stmt production.\n\tEnterDetach_stmt(c *Detach_stmtContext)\n\n\t// EnterDrop_stmt is called when entering the drop_stmt production.\n\tEnterDrop_stmt(c *Drop_stmtContext)\n\n\t// EnterExpr is called when entering the expr production.\n\tEnterExpr(c *ExprContext)\n\n\t// EnterRaise_function is called when entering the raise_function production.\n\tEnterRaise_function(c *Raise_functionContext)\n\n\t// EnterLiteral_value is called when entering the literal_value production.\n\tEnterLiteral_value(c *Literal_valueContext)\n\n\t// EnterInsert_stmt is called when entering the insert_stmt production.\n\tEnterInsert_stmt(c *Insert_stmtContext)\n\n\t// EnterReturning_clause is called when entering the returning_clause production.\n\tEnterReturning_clause(c *Returning_clauseContext)\n\n\t// EnterUpsert_clause is called when entering the upsert_clause production.\n\tEnterUpsert_clause(c *Upsert_clauseContext)\n\n\t// EnterPragma_stmt is called when entering the pragma_stmt production.\n\tEnterPragma_stmt(c *Pragma_stmtContext)\n\n\t// EnterPragma_value is called when entering the pragma_value production.\n\tEnterPragma_value(c *Pragma_valueContext)\n\n\t// EnterReindex_stmt is called when entering the reindex_stmt production.\n\tEnterReindex_stmt(c *Reindex_stmtContext)\n\n\t// EnterSelect_stmt is called when entering the select_stmt production.\n\tEnterSelect_stmt(c *Select_stmtContext)\n\n\t// EnterJoin_clause is called when entering the join_clause production.\n\tEnterJoin_clause(c *Join_clauseContext)\n\n\t// EnterSelect_core is called when entering the select_core production.\n\tEnterSelect_core(c *Select_coreContext)\n\n\t// EnterFactored_select_stmt is called when entering the factored_select_stmt production.\n\tEnterFactored_select_stmt(c *Factored_select_stmtContext)\n\n\t// EnterSimple_select_stmt is called when entering the simple_select_stmt production.\n\tEnterSimple_select_stmt(c *Simple_select_stmtContext)\n\n\t// EnterCompound_select_stmt is called when entering the compound_select_stmt production.\n\tEnterCompound_select_stmt(c *Compound_select_stmtContext)\n\n\t// EnterTable_or_subquery is called when entering the table_or_subquery production.\n\tEnterTable_or_subquery(c *Table_or_subqueryContext)\n\n\t// EnterResult_column is called when entering the result_column production.\n\tEnterResult_column(c *Result_columnContext)\n\n\t// EnterJoin_operator is called when entering the join_operator production.\n\tEnterJoin_operator(c *Join_operatorContext)\n\n\t// EnterJoin_constraint is called when entering the join_constraint production.\n\tEnterJoin_constraint(c *Join_constraintContext)\n\n\t// EnterCompound_operator is called when entering the compound_operator production.\n\tEnterCompound_operator(c *Compound_operatorContext)\n\n\t// EnterUpdate_stmt is called when entering the update_stmt production.\n\tEnterUpdate_stmt(c *Update_stmtContext)\n\n\t// EnterAssignment_list is called when entering the assignment_list production.\n\tEnterAssignment_list(c *Assignment_listContext)\n\n\t// EnterAssignment is called when entering the assignment production.\n\tEnterAssignment(c *AssignmentContext)\n\n\t// EnterColumn_name_list is called when entering the column_name_list production.\n\tEnterColumn_name_list(c *Column_name_listContext)\n\n\t// EnterUpdate_stmt_limited is called when entering the update_stmt_limited production.\n\tEnterUpdate_stmt_limited(c *Update_stmt_limitedContext)\n\n\t// EnterQualified_table_name is called when entering the qualified_table_name production.\n\tEnterQualified_table_name(c *Qualified_table_nameContext)\n\n\t// EnterVacuum_stmt is called when entering the vacuum_stmt production.\n\tEnterVacuum_stmt(c *Vacuum_stmtContext)\n\n\t// EnterFilter_clause is called when entering the filter_clause production.\n\tEnterFilter_clause(c *Filter_clauseContext)\n\n\t// EnterWindow_defn is called when entering the window_defn production.\n\tEnterWindow_defn(c *Window_defnContext)\n\n\t// EnterOver_clause is called when entering the over_clause production.\n\tEnterOver_clause(c *Over_clauseContext)\n\n\t// EnterFrame_spec is called when entering the frame_spec production.\n\tEnterFrame_spec(c *Frame_specContext)\n\n\t// EnterFrame_clause is called when entering the frame_clause production.\n\tEnterFrame_clause(c *Frame_clauseContext)\n\n\t// EnterSimple_function_invocation is called when entering the simple_function_invocation production.\n\tEnterSimple_function_invocation(c *Simple_function_invocationContext)\n\n\t// EnterAggregate_function_invocation is called when entering the aggregate_function_invocation production.\n\tEnterAggregate_function_invocation(c *Aggregate_function_invocationContext)\n\n\t// EnterWindow_function_invocation is called when entering the window_function_invocation production.\n\tEnterWindow_function_invocation(c *Window_function_invocationContext)\n\n\t// EnterCommon_table_stmt is called when entering the common_table_stmt production.\n\tEnterCommon_table_stmt(c *Common_table_stmtContext)\n\n\t// EnterOrder_by_stmt is called when entering the order_by_stmt production.\n\tEnterOrder_by_stmt(c *Order_by_stmtContext)\n\n\t// EnterLimit_stmt is called when entering the limit_stmt production.\n\tEnterLimit_stmt(c *Limit_stmtContext)\n\n\t// EnterOrdering_term is called when entering the ordering_term production.\n\tEnterOrdering_term(c *Ordering_termContext)\n\n\t// EnterAsc_desc is called when entering the asc_desc production.\n\tEnterAsc_desc(c *Asc_descContext)\n\n\t// EnterFrame_left is called when entering the frame_left production.\n\tEnterFrame_left(c *Frame_leftContext)\n\n\t// EnterFrame_right is called when entering the frame_right production.\n\tEnterFrame_right(c *Frame_rightContext)\n\n\t// EnterFrame_single is called when entering the frame_single production.\n\tEnterFrame_single(c *Frame_singleContext)\n\n\t// EnterWindow_function is called when entering the window_function production.\n\tEnterWindow_function(c *Window_functionContext)\n\n\t// EnterOffset is called when entering the offset production.\n\tEnterOffset(c *OffsetContext)\n\n\t// EnterDefault_value is called when entering the default_value production.\n\tEnterDefault_value(c *Default_valueContext)\n\n\t// EnterPartition_by is called when entering the partition_by production.\n\tEnterPartition_by(c *Partition_byContext)\n\n\t// EnterOrder_by_expr is called when entering the order_by_expr production.\n\tEnterOrder_by_expr(c *Order_by_exprContext)\n\n\t// EnterOrder_by_expr_asc_desc is called when entering the order_by_expr_asc_desc production.\n\tEnterOrder_by_expr_asc_desc(c *Order_by_expr_asc_descContext)\n\n\t// EnterExpr_asc_desc is called when entering the expr_asc_desc production.\n\tEnterExpr_asc_desc(c *Expr_asc_descContext)\n\n\t// EnterInitial_select is called when entering the initial_select production.\n\tEnterInitial_select(c *Initial_selectContext)\n\n\t// EnterRecursive_select is called when entering the recursive_select production.\n\tEnterRecursive_select(c *Recursive_selectContext)\n\n\t// EnterUnary_operator is called when entering the unary_operator production.\n\tEnterUnary_operator(c *Unary_operatorContext)\n\n\t// EnterError_message is called when entering the error_message production.\n\tEnterError_message(c *Error_messageContext)\n\n\t// EnterModule_argument is called when entering the module_argument production.\n\tEnterModule_argument(c *Module_argumentContext)\n\n\t// EnterColumn_alias is called when entering the column_alias production.\n\tEnterColumn_alias(c *Column_aliasContext)\n\n\t// EnterKeyword is called when entering the keyword production.\n\tEnterKeyword(c *KeywordContext)\n\n\t// EnterName is called when entering the name production.\n\tEnterName(c *NameContext)\n\n\t// EnterFunction_name is called when entering the function_name production.\n\tEnterFunction_name(c *Function_nameContext)\n\n\t// EnterSchema_name is called when entering the schema_name production.\n\tEnterSchema_name(c *Schema_nameContext)\n\n\t// EnterTable_name is called when entering the table_name production.\n\tEnterTable_name(c *Table_nameContext)\n\n\t// EnterTable_or_index_name is called when entering the table_or_index_name production.\n\tEnterTable_or_index_name(c *Table_or_index_nameContext)\n\n\t// EnterColumn_name is called when entering the column_name production.\n\tEnterColumn_name(c *Column_nameContext)\n\n\t// EnterCollation_name is called when entering the collation_name production.\n\tEnterCollation_name(c *Collation_nameContext)\n\n\t// EnterForeign_table is called when entering the foreign_table production.\n\tEnterForeign_table(c *Foreign_tableContext)\n\n\t// EnterIndex_name is called when entering the index_name production.\n\tEnterIndex_name(c *Index_nameContext)\n\n\t// EnterTrigger_name is called when entering the trigger_name production.\n\tEnterTrigger_name(c *Trigger_nameContext)\n\n\t// EnterView_name is called when entering the view_name production.\n\tEnterView_name(c *View_nameContext)\n\n\t// EnterModule_name is called when entering the module_name production.\n\tEnterModule_name(c *Module_nameContext)\n\n\t// EnterPragma_name is called when entering the pragma_name production.\n\tEnterPragma_name(c *Pragma_nameContext)\n\n\t// EnterSavepoint_name is called when entering the savepoint_name production.\n\tEnterSavepoint_name(c *Savepoint_nameContext)\n\n\t// EnterTable_alias is called when entering the table_alias production.\n\tEnterTable_alias(c *Table_aliasContext)\n\n\t// EnterTransaction_name is called when entering the transaction_name production.\n\tEnterTransaction_name(c *Transaction_nameContext)\n\n\t// EnterWindow_name is called when entering the window_name production.\n\tEnterWindow_name(c *Window_nameContext)\n\n\t// EnterAlias is called when entering the alias production.\n\tEnterAlias(c *AliasContext)\n\n\t// EnterFilename is called when entering the filename production.\n\tEnterFilename(c *FilenameContext)\n\n\t// EnterBase_window_name is called when entering the base_window_name production.\n\tEnterBase_window_name(c *Base_window_nameContext)\n\n\t// EnterSimple_func is called when entering the simple_func production.\n\tEnterSimple_func(c *Simple_funcContext)\n\n\t// EnterAggregate_func is called when entering the aggregate_func production.\n\tEnterAggregate_func(c *Aggregate_funcContext)\n\n\t// EnterTable_function_name is called when entering the table_function_name production.\n\tEnterTable_function_name(c *Table_function_nameContext)\n\n\t// EnterAny_name is called when entering the any_name production.\n\tEnterAny_name(c *Any_nameContext)\n\n\t// ExitParse is called when exiting the parse production.\n\tExitParse(c *ParseContext)\n\n\t// ExitSql_stmt_list is called when exiting the sql_stmt_list production.\n\tExitSql_stmt_list(c *Sql_stmt_listContext)\n\n\t// ExitSql_stmt is called when exiting the sql_stmt production.\n\tExitSql_stmt(c *Sql_stmtContext)\n\n\t// ExitAlter_table_stmt is called when exiting the alter_table_stmt production.\n\tExitAlter_table_stmt(c *Alter_table_stmtContext)\n\n\t// ExitAnalyze_stmt is called when exiting the analyze_stmt production.\n\tExitAnalyze_stmt(c *Analyze_stmtContext)\n\n\t// ExitAttach_stmt is called when exiting the attach_stmt production.\n\tExitAttach_stmt(c *Attach_stmtContext)\n\n\t// ExitBegin_stmt is called when exiting the begin_stmt production.\n\tExitBegin_stmt(c *Begin_stmtContext)\n\n\t// ExitCommit_stmt is called when exiting the commit_stmt production.\n\tExitCommit_stmt(c *Commit_stmtContext)\n\n\t// ExitRollback_stmt is called when exiting the rollback_stmt production.\n\tExitRollback_stmt(c *Rollback_stmtContext)\n\n\t// ExitSavepoint_stmt is called when exiting the savepoint_stmt production.\n\tExitSavepoint_stmt(c *Savepoint_stmtContext)\n\n\t// ExitRelease_stmt is called when exiting the release_stmt production.\n\tExitRelease_stmt(c *Release_stmtContext)\n\n\t// ExitCreate_index_stmt is called when exiting the create_index_stmt production.\n\tExitCreate_index_stmt(c *Create_index_stmtContext)\n\n\t// ExitIndexed_column is called when exiting the indexed_column production.\n\tExitIndexed_column(c *Indexed_columnContext)\n\n\t// ExitCreate_table_stmt is called when exiting the create_table_stmt production.\n\tExitCreate_table_stmt(c *Create_table_stmtContext)\n\n\t// ExitColumn_def is called when exiting the column_def production.\n\tExitColumn_def(c *Column_defContext)\n\n\t// ExitType_name is called when exiting the type_name production.\n\tExitType_name(c *Type_nameContext)\n\n\t// ExitColumn_constraint is called when exiting the column_constraint production.\n\tExitColumn_constraint(c *Column_constraintContext)\n\n\t// ExitSigned_number is called when exiting the signed_number production.\n\tExitSigned_number(c *Signed_numberContext)\n\n\t// ExitTable_constraint is called when exiting the table_constraint production.\n\tExitTable_constraint(c *Table_constraintContext)\n\n\t// ExitForeign_key_clause is called when exiting the foreign_key_clause production.\n\tExitForeign_key_clause(c *Foreign_key_clauseContext)\n\n\t// ExitConflict_clause is called when exiting the conflict_clause production.\n\tExitConflict_clause(c *Conflict_clauseContext)\n\n\t// ExitCreate_trigger_stmt is called when exiting the create_trigger_stmt production.\n\tExitCreate_trigger_stmt(c *Create_trigger_stmtContext)\n\n\t// ExitCreate_view_stmt is called when exiting the create_view_stmt production.\n\tExitCreate_view_stmt(c *Create_view_stmtContext)\n\n\t// ExitCreate_virtual_table_stmt is called when exiting the create_virtual_table_stmt production.\n\tExitCreate_virtual_table_stmt(c *Create_virtual_table_stmtContext)\n\n\t// ExitWith_clause is called when exiting the with_clause production.\n\tExitWith_clause(c *With_clauseContext)\n\n\t// ExitCte_table_name is called when exiting the cte_table_name production.\n\tExitCte_table_name(c *Cte_table_nameContext)\n\n\t// ExitRecursive_cte is called when exiting the recursive_cte production.\n\tExitRecursive_cte(c *Recursive_cteContext)\n\n\t// ExitCommon_table_expression is called when exiting the common_table_expression production.\n\tExitCommon_table_expression(c *Common_table_expressionContext)\n\n\t// ExitDelete_stmt is called when exiting the delete_stmt production.\n\tExitDelete_stmt(c *Delete_stmtContext)\n\n\t// ExitDelete_stmt_limited is called when exiting the delete_stmt_limited production.\n\tExitDelete_stmt_limited(c *Delete_stmt_limitedContext)\n\n\t// ExitDetach_stmt is called when exiting the detach_stmt production.\n\tExitDetach_stmt(c *Detach_stmtContext)\n\n\t// ExitDrop_stmt is called when exiting the drop_stmt production.\n\tExitDrop_stmt(c *Drop_stmtContext)\n\n\t// ExitExpr is called when exiting the expr production.\n\tExitExpr(c *ExprContext)\n\n\t// ExitRaise_function is called when exiting the raise_function production.\n\tExitRaise_function(c *Raise_functionContext)\n\n\t// ExitLiteral_value is called when exiting the literal_value production.\n\tExitLiteral_value(c *Literal_valueContext)\n\n\t// ExitInsert_stmt is called when exiting the insert_stmt production.\n\tExitInsert_stmt(c *Insert_stmtContext)\n\n\t// ExitReturning_clause is called when exiting the returning_clause production.\n\tExitReturning_clause(c *Returning_clauseContext)\n\n\t// ExitUpsert_clause is called when exiting the upsert_clause production.\n\tExitUpsert_clause(c *Upsert_clauseContext)\n\n\t// ExitPragma_stmt is called when exiting the pragma_stmt production.\n\tExitPragma_stmt(c *Pragma_stmtContext)\n\n\t// ExitPragma_value is called when exiting the pragma_value production.\n\tExitPragma_value(c *Pragma_valueContext)\n\n\t// ExitReindex_stmt is called when exiting the reindex_stmt production.\n\tExitReindex_stmt(c *Reindex_stmtContext)\n\n\t// ExitSelect_stmt is called when exiting the select_stmt production.\n\tExitSelect_stmt(c *Select_stmtContext)\n\n\t// ExitJoin_clause is called when exiting the join_clause production.\n\tExitJoin_clause(c *Join_clauseContext)\n\n\t// ExitSelect_core is called when exiting the select_core production.\n\tExitSelect_core(c *Select_coreContext)\n\n\t// ExitFactored_select_stmt is called when exiting the factored_select_stmt production.\n\tExitFactored_select_stmt(c *Factored_select_stmtContext)\n\n\t// ExitSimple_select_stmt is called when exiting the simple_select_stmt production.\n\tExitSimple_select_stmt(c *Simple_select_stmtContext)\n\n\t// ExitCompound_select_stmt is called when exiting the compound_select_stmt production.\n\tExitCompound_select_stmt(c *Compound_select_stmtContext)\n\n\t// ExitTable_or_subquery is called when exiting the table_or_subquery production.\n\tExitTable_or_subquery(c *Table_or_subqueryContext)\n\n\t// ExitResult_column is called when exiting the result_column production.\n\tExitResult_column(c *Result_columnContext)\n\n\t// ExitJoin_operator is called when exiting the join_operator production.\n\tExitJoin_operator(c *Join_operatorContext)\n\n\t// ExitJoin_constraint is called when exiting the join_constraint production.\n\tExitJoin_constraint(c *Join_constraintContext)\n\n\t// ExitCompound_operator is called when exiting the compound_operator production.\n\tExitCompound_operator(c *Compound_operatorContext)\n\n\t// ExitUpdate_stmt is called when exiting the update_stmt production.\n\tExitUpdate_stmt(c *Update_stmtContext)\n\n\t// ExitAssignment_list is called when exiting the assignment_list production.\n\tExitAssignment_list(c *Assignment_listContext)\n\n\t// ExitAssignment is called when exiting the assignment production.\n\tExitAssignment(c *AssignmentContext)\n\n\t// ExitColumn_name_list is called when exiting the column_name_list production.\n\tExitColumn_name_list(c *Column_name_listContext)\n\n\t// ExitUpdate_stmt_limited is called when exiting the update_stmt_limited production.\n\tExitUpdate_stmt_limited(c *Update_stmt_limitedContext)\n\n\t// ExitQualified_table_name is called when exiting the qualified_table_name production.\n\tExitQualified_table_name(c *Qualified_table_nameContext)\n\n\t// ExitVacuum_stmt is called when exiting the vacuum_stmt production.\n\tExitVacuum_stmt(c *Vacuum_stmtContext)\n\n\t// ExitFilter_clause is called when exiting the filter_clause production.\n\tExitFilter_clause(c *Filter_clauseContext)\n\n\t// ExitWindow_defn is called when exiting the window_defn production.\n\tExitWindow_defn(c *Window_defnContext)\n\n\t// ExitOver_clause is called when exiting the over_clause production.\n\tExitOver_clause(c *Over_clauseContext)\n\n\t// ExitFrame_spec is called when exiting the frame_spec production.\n\tExitFrame_spec(c *Frame_specContext)\n\n\t// ExitFrame_clause is called when exiting the frame_clause production.\n\tExitFrame_clause(c *Frame_clauseContext)\n\n\t// ExitSimple_function_invocation is called when exiting the simple_function_invocation production.\n\tExitSimple_function_invocation(c *Simple_function_invocationContext)\n\n\t// ExitAggregate_function_invocation is called when exiting the aggregate_function_invocation production.\n\tExitAggregate_function_invocation(c *Aggregate_function_invocationContext)\n\n\t// ExitWindow_function_invocation is called when exiting the window_function_invocation production.\n\tExitWindow_function_invocation(c *Window_function_invocationContext)\n\n\t// ExitCommon_table_stmt is called when exiting the common_table_stmt production.\n\tExitCommon_table_stmt(c *Common_table_stmtContext)\n\n\t// ExitOrder_by_stmt is called when exiting the order_by_stmt production.\n\tExitOrder_by_stmt(c *Order_by_stmtContext)\n\n\t// ExitLimit_stmt is called when exiting the limit_stmt production.\n\tExitLimit_stmt(c *Limit_stmtContext)\n\n\t// ExitOrdering_term is called when exiting the ordering_term production.\n\tExitOrdering_term(c *Ordering_termContext)\n\n\t// ExitAsc_desc is called when exiting the asc_desc production.\n\tExitAsc_desc(c *Asc_descContext)\n\n\t// ExitFrame_left is called when exiting the frame_left production.\n\tExitFrame_left(c *Frame_leftContext)\n\n\t// ExitFrame_right is called when exiting the frame_right production.\n\tExitFrame_right(c *Frame_rightContext)\n\n\t// ExitFrame_single is called when exiting the frame_single production.\n\tExitFrame_single(c *Frame_singleContext)\n\n\t// ExitWindow_function is called when exiting the window_function production.\n\tExitWindow_function(c *Window_functionContext)\n\n\t// ExitOffset is called when exiting the offset production.\n\tExitOffset(c *OffsetContext)\n\n\t// ExitDefault_value is called when exiting the default_value production.\n\tExitDefault_value(c *Default_valueContext)\n\n\t// ExitPartition_by is called when exiting the partition_by production.\n\tExitPartition_by(c *Partition_byContext)\n\n\t// ExitOrder_by_expr is called when exiting the order_by_expr production.\n\tExitOrder_by_expr(c *Order_by_exprContext)\n\n\t// ExitOrder_by_expr_asc_desc is called when exiting the order_by_expr_asc_desc production.\n\tExitOrder_by_expr_asc_desc(c *Order_by_expr_asc_descContext)\n\n\t// ExitExpr_asc_desc is called when exiting the expr_asc_desc production.\n\tExitExpr_asc_desc(c *Expr_asc_descContext)\n\n\t// ExitInitial_select is called when exiting the initial_select production.\n\tExitInitial_select(c *Initial_selectContext)\n\n\t// ExitRecursive_select is called when exiting the recursive_select production.\n\tExitRecursive_select(c *Recursive_selectContext)\n\n\t// ExitUnary_operator is called when exiting the unary_operator production.\n\tExitUnary_operator(c *Unary_operatorContext)\n\n\t// ExitError_message is called when exiting the error_message production.\n\tExitError_message(c *Error_messageContext)\n\n\t// ExitModule_argument is called when exiting the module_argument production.\n\tExitModule_argument(c *Module_argumentContext)\n\n\t// ExitColumn_alias is called when exiting the column_alias production.\n\tExitColumn_alias(c *Column_aliasContext)\n\n\t// ExitKeyword is called when exiting the keyword production.\n\tExitKeyword(c *KeywordContext)\n\n\t// ExitName is called when exiting the name production.\n\tExitName(c *NameContext)\n\n\t// ExitFunction_name is called when exiting the function_name production.\n\tExitFunction_name(c *Function_nameContext)\n\n\t// ExitSchema_name is called when exiting the schema_name production.\n\tExitSchema_name(c *Schema_nameContext)\n\n\t// ExitTable_name is called when exiting the table_name production.\n\tExitTable_name(c *Table_nameContext)\n\n\t// ExitTable_or_index_name is called when exiting the table_or_index_name production.\n\tExitTable_or_index_name(c *Table_or_index_nameContext)\n\n\t// ExitColumn_name is called when exiting the column_name production.\n\tExitColumn_name(c *Column_nameContext)\n\n\t// ExitCollation_name is called when exiting the collation_name production.\n\tExitCollation_name(c *Collation_nameContext)\n\n\t// ExitForeign_table is called when exiting the foreign_table production.\n\tExitForeign_table(c *Foreign_tableContext)\n\n\t// ExitIndex_name is called when exiting the index_name production.\n\tExitIndex_name(c *Index_nameContext)\n\n\t// ExitTrigger_name is called when exiting the trigger_name production.\n\tExitTrigger_name(c *Trigger_nameContext)\n\n\t// ExitView_name is called when exiting the view_name production.\n\tExitView_name(c *View_nameContext)\n\n\t// ExitModule_name is called when exiting the module_name production.\n\tExitModule_name(c *Module_nameContext)\n\n\t// ExitPragma_name is called when exiting the pragma_name production.\n\tExitPragma_name(c *Pragma_nameContext)\n\n\t// ExitSavepoint_name is called when exiting the savepoint_name production.\n\tExitSavepoint_name(c *Savepoint_nameContext)\n\n\t// ExitTable_alias is called when exiting the table_alias production.\n\tExitTable_alias(c *Table_aliasContext)\n\n\t// ExitTransaction_name is called when exiting the transaction_name production.\n\tExitTransaction_name(c *Transaction_nameContext)\n\n\t// ExitWindow_name is called when exiting the window_name production.\n\tExitWindow_name(c *Window_nameContext)\n\n\t// ExitAlias is called when exiting the alias production.\n\tExitAlias(c *AliasContext)\n\n\t// ExitFilename is called when exiting the filename production.\n\tExitFilename(c *FilenameContext)\n\n\t// ExitBase_window_name is called when exiting the base_window_name production.\n\tExitBase_window_name(c *Base_window_nameContext)\n\n\t// ExitSimple_func is called when exiting the simple_func production.\n\tExitSimple_func(c *Simple_funcContext)\n\n\t// ExitAggregate_func is called when exiting the aggregate_func production.\n\tExitAggregate_func(c *Aggregate_funcContext)\n\n\t// ExitTable_function_name is called when exiting the table_function_name production.\n\tExitTable_function_name(c *Table_function_nameContext)\n\n\t// ExitAny_name is called when exiting the any_name production.\n\tExitAny_name(c *Any_nameContext)\n}\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqliteparse/parser_visitor.go",
    "content": "// Code generated from Parser.g4 by ANTLR 4.13.1. DO NOT EDIT.\n\npackage sqliteparse // Parser\nimport \"github.com/antlr4-go/antlr/v4\"\n\n// A complete Visitor for a parse tree produced by Parser.\ntype ParserVisitor interface {\n\tantlr.ParseTreeVisitor\n\n\t// Visit a parse tree produced by Parser#parse.\n\tVisitParse(ctx *ParseContext) interface{}\n\n\t// Visit a parse tree produced by Parser#sql_stmt_list.\n\tVisitSql_stmt_list(ctx *Sql_stmt_listContext) interface{}\n\n\t// Visit a parse tree produced by Parser#sql_stmt.\n\tVisitSql_stmt(ctx *Sql_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#alter_table_stmt.\n\tVisitAlter_table_stmt(ctx *Alter_table_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#analyze_stmt.\n\tVisitAnalyze_stmt(ctx *Analyze_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#attach_stmt.\n\tVisitAttach_stmt(ctx *Attach_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#begin_stmt.\n\tVisitBegin_stmt(ctx *Begin_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#commit_stmt.\n\tVisitCommit_stmt(ctx *Commit_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#rollback_stmt.\n\tVisitRollback_stmt(ctx *Rollback_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#savepoint_stmt.\n\tVisitSavepoint_stmt(ctx *Savepoint_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#release_stmt.\n\tVisitRelease_stmt(ctx *Release_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#create_index_stmt.\n\tVisitCreate_index_stmt(ctx *Create_index_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#indexed_column.\n\tVisitIndexed_column(ctx *Indexed_columnContext) interface{}\n\n\t// Visit a parse tree produced by Parser#create_table_stmt.\n\tVisitCreate_table_stmt(ctx *Create_table_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#column_def.\n\tVisitColumn_def(ctx *Column_defContext) interface{}\n\n\t// Visit a parse tree produced by Parser#type_name.\n\tVisitType_name(ctx *Type_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#column_constraint.\n\tVisitColumn_constraint(ctx *Column_constraintContext) interface{}\n\n\t// Visit a parse tree produced by Parser#signed_number.\n\tVisitSigned_number(ctx *Signed_numberContext) interface{}\n\n\t// Visit a parse tree produced by Parser#table_constraint.\n\tVisitTable_constraint(ctx *Table_constraintContext) interface{}\n\n\t// Visit a parse tree produced by Parser#foreign_key_clause.\n\tVisitForeign_key_clause(ctx *Foreign_key_clauseContext) interface{}\n\n\t// Visit a parse tree produced by Parser#conflict_clause.\n\tVisitConflict_clause(ctx *Conflict_clauseContext) interface{}\n\n\t// Visit a parse tree produced by Parser#create_trigger_stmt.\n\tVisitCreate_trigger_stmt(ctx *Create_trigger_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#create_view_stmt.\n\tVisitCreate_view_stmt(ctx *Create_view_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#create_virtual_table_stmt.\n\tVisitCreate_virtual_table_stmt(ctx *Create_virtual_table_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#with_clause.\n\tVisitWith_clause(ctx *With_clauseContext) interface{}\n\n\t// Visit a parse tree produced by Parser#cte_table_name.\n\tVisitCte_table_name(ctx *Cte_table_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#recursive_cte.\n\tVisitRecursive_cte(ctx *Recursive_cteContext) interface{}\n\n\t// Visit a parse tree produced by Parser#common_table_expression.\n\tVisitCommon_table_expression(ctx *Common_table_expressionContext) interface{}\n\n\t// Visit a parse tree produced by Parser#delete_stmt.\n\tVisitDelete_stmt(ctx *Delete_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#delete_stmt_limited.\n\tVisitDelete_stmt_limited(ctx *Delete_stmt_limitedContext) interface{}\n\n\t// Visit a parse tree produced by Parser#detach_stmt.\n\tVisitDetach_stmt(ctx *Detach_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#drop_stmt.\n\tVisitDrop_stmt(ctx *Drop_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#expr.\n\tVisitExpr(ctx *ExprContext) interface{}\n\n\t// Visit a parse tree produced by Parser#raise_function.\n\tVisitRaise_function(ctx *Raise_functionContext) interface{}\n\n\t// Visit a parse tree produced by Parser#literal_value.\n\tVisitLiteral_value(ctx *Literal_valueContext) interface{}\n\n\t// Visit a parse tree produced by Parser#insert_stmt.\n\tVisitInsert_stmt(ctx *Insert_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#returning_clause.\n\tVisitReturning_clause(ctx *Returning_clauseContext) interface{}\n\n\t// Visit a parse tree produced by Parser#upsert_clause.\n\tVisitUpsert_clause(ctx *Upsert_clauseContext) interface{}\n\n\t// Visit a parse tree produced by Parser#pragma_stmt.\n\tVisitPragma_stmt(ctx *Pragma_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#pragma_value.\n\tVisitPragma_value(ctx *Pragma_valueContext) interface{}\n\n\t// Visit a parse tree produced by Parser#reindex_stmt.\n\tVisitReindex_stmt(ctx *Reindex_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#select_stmt.\n\tVisitSelect_stmt(ctx *Select_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#join_clause.\n\tVisitJoin_clause(ctx *Join_clauseContext) interface{}\n\n\t// Visit a parse tree produced by Parser#select_core.\n\tVisitSelect_core(ctx *Select_coreContext) interface{}\n\n\t// Visit a parse tree produced by Parser#factored_select_stmt.\n\tVisitFactored_select_stmt(ctx *Factored_select_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#simple_select_stmt.\n\tVisitSimple_select_stmt(ctx *Simple_select_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#compound_select_stmt.\n\tVisitCompound_select_stmt(ctx *Compound_select_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#table_or_subquery.\n\tVisitTable_or_subquery(ctx *Table_or_subqueryContext) interface{}\n\n\t// Visit a parse tree produced by Parser#result_column.\n\tVisitResult_column(ctx *Result_columnContext) interface{}\n\n\t// Visit a parse tree produced by Parser#join_operator.\n\tVisitJoin_operator(ctx *Join_operatorContext) interface{}\n\n\t// Visit a parse tree produced by Parser#join_constraint.\n\tVisitJoin_constraint(ctx *Join_constraintContext) interface{}\n\n\t// Visit a parse tree produced by Parser#compound_operator.\n\tVisitCompound_operator(ctx *Compound_operatorContext) interface{}\n\n\t// Visit a parse tree produced by Parser#update_stmt.\n\tVisitUpdate_stmt(ctx *Update_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#assignment_list.\n\tVisitAssignment_list(ctx *Assignment_listContext) interface{}\n\n\t// Visit a parse tree produced by Parser#assignment.\n\tVisitAssignment(ctx *AssignmentContext) interface{}\n\n\t// Visit a parse tree produced by Parser#column_name_list.\n\tVisitColumn_name_list(ctx *Column_name_listContext) interface{}\n\n\t// Visit a parse tree produced by Parser#update_stmt_limited.\n\tVisitUpdate_stmt_limited(ctx *Update_stmt_limitedContext) interface{}\n\n\t// Visit a parse tree produced by Parser#qualified_table_name.\n\tVisitQualified_table_name(ctx *Qualified_table_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#vacuum_stmt.\n\tVisitVacuum_stmt(ctx *Vacuum_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#filter_clause.\n\tVisitFilter_clause(ctx *Filter_clauseContext) interface{}\n\n\t// Visit a parse tree produced by Parser#window_defn.\n\tVisitWindow_defn(ctx *Window_defnContext) interface{}\n\n\t// Visit a parse tree produced by Parser#over_clause.\n\tVisitOver_clause(ctx *Over_clauseContext) interface{}\n\n\t// Visit a parse tree produced by Parser#frame_spec.\n\tVisitFrame_spec(ctx *Frame_specContext) interface{}\n\n\t// Visit a parse tree produced by Parser#frame_clause.\n\tVisitFrame_clause(ctx *Frame_clauseContext) interface{}\n\n\t// Visit a parse tree produced by Parser#simple_function_invocation.\n\tVisitSimple_function_invocation(ctx *Simple_function_invocationContext) interface{}\n\n\t// Visit a parse tree produced by Parser#aggregate_function_invocation.\n\tVisitAggregate_function_invocation(ctx *Aggregate_function_invocationContext) interface{}\n\n\t// Visit a parse tree produced by Parser#window_function_invocation.\n\tVisitWindow_function_invocation(ctx *Window_function_invocationContext) interface{}\n\n\t// Visit a parse tree produced by Parser#common_table_stmt.\n\tVisitCommon_table_stmt(ctx *Common_table_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#order_by_stmt.\n\tVisitOrder_by_stmt(ctx *Order_by_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#limit_stmt.\n\tVisitLimit_stmt(ctx *Limit_stmtContext) interface{}\n\n\t// Visit a parse tree produced by Parser#ordering_term.\n\tVisitOrdering_term(ctx *Ordering_termContext) interface{}\n\n\t// Visit a parse tree produced by Parser#asc_desc.\n\tVisitAsc_desc(ctx *Asc_descContext) interface{}\n\n\t// Visit a parse tree produced by Parser#frame_left.\n\tVisitFrame_left(ctx *Frame_leftContext) interface{}\n\n\t// Visit a parse tree produced by Parser#frame_right.\n\tVisitFrame_right(ctx *Frame_rightContext) interface{}\n\n\t// Visit a parse tree produced by Parser#frame_single.\n\tVisitFrame_single(ctx *Frame_singleContext) interface{}\n\n\t// Visit a parse tree produced by Parser#window_function.\n\tVisitWindow_function(ctx *Window_functionContext) interface{}\n\n\t// Visit a parse tree produced by Parser#offset.\n\tVisitOffset(ctx *OffsetContext) interface{}\n\n\t// Visit a parse tree produced by Parser#default_value.\n\tVisitDefault_value(ctx *Default_valueContext) interface{}\n\n\t// Visit a parse tree produced by Parser#partition_by.\n\tVisitPartition_by(ctx *Partition_byContext) interface{}\n\n\t// Visit a parse tree produced by Parser#order_by_expr.\n\tVisitOrder_by_expr(ctx *Order_by_exprContext) interface{}\n\n\t// Visit a parse tree produced by Parser#order_by_expr_asc_desc.\n\tVisitOrder_by_expr_asc_desc(ctx *Order_by_expr_asc_descContext) interface{}\n\n\t// Visit a parse tree produced by Parser#expr_asc_desc.\n\tVisitExpr_asc_desc(ctx *Expr_asc_descContext) interface{}\n\n\t// Visit a parse tree produced by Parser#initial_select.\n\tVisitInitial_select(ctx *Initial_selectContext) interface{}\n\n\t// Visit a parse tree produced by Parser#recursive_select.\n\tVisitRecursive_select(ctx *Recursive_selectContext) interface{}\n\n\t// Visit a parse tree produced by Parser#unary_operator.\n\tVisitUnary_operator(ctx *Unary_operatorContext) interface{}\n\n\t// Visit a parse tree produced by Parser#error_message.\n\tVisitError_message(ctx *Error_messageContext) interface{}\n\n\t// Visit a parse tree produced by Parser#module_argument.\n\tVisitModule_argument(ctx *Module_argumentContext) interface{}\n\n\t// Visit a parse tree produced by Parser#column_alias.\n\tVisitColumn_alias(ctx *Column_aliasContext) interface{}\n\n\t// Visit a parse tree produced by Parser#keyword.\n\tVisitKeyword(ctx *KeywordContext) interface{}\n\n\t// Visit a parse tree produced by Parser#name.\n\tVisitName(ctx *NameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#function_name.\n\tVisitFunction_name(ctx *Function_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#schema_name.\n\tVisitSchema_name(ctx *Schema_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#table_name.\n\tVisitTable_name(ctx *Table_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#table_or_index_name.\n\tVisitTable_or_index_name(ctx *Table_or_index_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#column_name.\n\tVisitColumn_name(ctx *Column_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#collation_name.\n\tVisitCollation_name(ctx *Collation_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#foreign_table.\n\tVisitForeign_table(ctx *Foreign_tableContext) interface{}\n\n\t// Visit a parse tree produced by Parser#index_name.\n\tVisitIndex_name(ctx *Index_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#trigger_name.\n\tVisitTrigger_name(ctx *Trigger_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#view_name.\n\tVisitView_name(ctx *View_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#module_name.\n\tVisitModule_name(ctx *Module_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#pragma_name.\n\tVisitPragma_name(ctx *Pragma_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#savepoint_name.\n\tVisitSavepoint_name(ctx *Savepoint_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#table_alias.\n\tVisitTable_alias(ctx *Table_aliasContext) interface{}\n\n\t// Visit a parse tree produced by Parser#transaction_name.\n\tVisitTransaction_name(ctx *Transaction_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#window_name.\n\tVisitWindow_name(ctx *Window_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#alias.\n\tVisitAlias(ctx *AliasContext) interface{}\n\n\t// Visit a parse tree produced by Parser#filename.\n\tVisitFilename(ctx *FilenameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#base_window_name.\n\tVisitBase_window_name(ctx *Base_window_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#simple_func.\n\tVisitSimple_func(ctx *Simple_funcContext) interface{}\n\n\t// Visit a parse tree produced by Parser#aggregate_func.\n\tVisitAggregate_func(ctx *Aggregate_funcContext) interface{}\n\n\t// Visit a parse tree produced by Parser#table_function_name.\n\tVisitTable_function_name(ctx *Table_function_nameContext) interface{}\n\n\t// Visit a parse tree produced by Parser#any_name.\n\tVisitAny_name(ctx *Any_nameContext) interface{}\n}\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqliteparse/sqliteparse_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage sqliteparse\n\nimport (\n\t\"errors\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\ntype FileParser struct{}\n\nfunc (*FileParser) ColumnFilledBefore([]*migrate.Stmt, *schema.Table, *schema.Column, int) (bool, error) {\n\treturn false, errors.New(\"unimplemented\")\n}\n\nfunc (*FileParser) CreateViewAfter([]*migrate.Stmt, string, string, int) (bool, error) {\n\treturn false, errors.New(\"unimplemented\")\n}\n\nfunc (*FileParser) FixChange(_ migrate.Driver, _ string, changes schema.Changes) (schema.Changes, error) {\n\treturn changes, nil // Unimplemented.\n}\n"
  },
  {
    "path": "cmd/atlas/internal/sqlparse/sqlparse.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlparse\n\nimport (\n\t\"sync\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/sqlparse/myparse\"\n\t\"ariga.io/atlas/cmd/atlas/internal/sqlparse/pgparse\"\n\t\"ariga.io/atlas/cmd/atlas/internal/sqlparse/sqliteparse\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/mysql\"\n\t\"ariga.io/atlas/sql/postgres\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlite\"\n)\n\n// A Parser represents an SQL file parser used to fix, search and enrich schema.Changes.\ntype Parser interface {\n\t// FixChange fixes the changes according to the given statement.\n\tFixChange(d migrate.Driver, stmt string, changes schema.Changes) (schema.Changes, error)\n\n\t// ColumnFilledBefore checks if the column was filled with values before the given position\n\t// in the file. For example:\n\t//\n\t//\tUPDATE <table> SET <column> = <value>\n\t//\tUPDATE <table> SET <column> = <value> WHERE <column> IS NULL\n\t//\n\tColumnFilledBefore([]*migrate.Stmt, *schema.Table, *schema.Column, int) (bool, error)\n\n\t// CreateViewAfter checks if a view was created after the position with the given name\n\t// to a table. For example:\n\t//\n\t//\tALTER TABLE `users` RENAME TO `Users`\n\t//\tCREATE VIEW `users` AS SELECT * FROM `Users`\n\t//\n\tCreateViewAfter(stmts []*migrate.Stmt, old, new string, pos int) (bool, error)\n}\n\n// drivers specific fixers.\nvar drivers sync.Map\n\n// Register a fixer with the given name.\nfunc Register(name string, f Parser) {\n\tdrivers.Store(name, f)\n}\n\n// ParserFor returns a ChangesFixer for the given driver.\nfunc ParserFor(name string) Parser {\n\tf, ok := drivers.Load(name)\n\tif ok {\n\t\treturn f.(Parser)\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tRegister(mysql.DriverName, &myparse.FileParser{})\n\tRegister(postgres.DriverName, &pgparse.Parser{})\n\tRegister(sqlite.DriverName, &sqliteparse.FileParser{})\n}\n"
  },
  {
    "path": "cmd/atlas/main.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdapi\"\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdapi/vercheck\"\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdlog\"\n\t_ \"ariga.io/atlas/cmd/atlas/internal/docker\"\n\t_ \"ariga.io/atlas/sql/mysql\"\n\t_ \"ariga.io/atlas/sql/mysql/mysqlcheck\"\n\t_ \"ariga.io/atlas/sql/postgres\"\n\t_ \"ariga.io/atlas/sql/postgres/postgrescheck\"\n\t_ \"ariga.io/atlas/sql/sqlite\"\n\t_ \"ariga.io/atlas/sql/sqlite/sqlitecheck\"\n\n\t_ \"github.com/go-sql-driver/mysql\"\n\t_ \"github.com/lib/pq\"\n\t\"github.com/mattn/go-isatty\"\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"github.com/spf13/cobra\"\n\t_ \"github.com/tursodatabase/libsql-client-go/libsql\"\n\t\"golang.org/x/mod/semver\"\n)\n\nfunc main() {\n\tcmdapi.Root.SetOut(os.Stdout)\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\tgo func() {\n\t\t// On first signal seen, cancel the context. On the second signal, force stop immediately.\n\t\tstop := make(chan os.Signal, 2)\n\t\tdefer close(stop)\n\t\tsignal.Notify(stop, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)\n\t\tdefer signal.Stop(stop)\n\t\t<-stop   // wait for first interrupt\n\t\tcancel() // cancel context to gracefully stop\n\t\tfmt.Fprintln(cmdapi.Root.OutOrStdout(), \"\\ninterrupt received, wait for exit or ^C to terminate\")\n\t\t// Wait for the context to be canceled. Issuing a second interrupt will cause the process to force stop.\n\t\t<-stop // will not block if no signal received due to main routine exiting\n\t\tos.Exit(1)\n\t}()\n\tctx, err := extendContext(ctx)\n\tcobra.CheckErr(err)\n\tctx, done := initialize(ctx)\n\tupdate := checkForUpdate(ctx)\n\terr = cmdapi.Root.ExecuteContext(ctx)\n\tif u := update(); u != \"\" {\n\t\t_ = cmdlog.WarnOnce(os.Stderr, cmdlog.ColorCyan(u))\n\t}\n\tdone(err)\n\tif err != nil {\n\t\tos.Exit(1)\n\t}\n}\n\nconst (\n\t// envNoUpdate when enabled it cancels checking for update\n\tenvNoUpdate = \"ATLAS_NO_UPDATE_NOTIFIER\"\n\tvercheckURL = \"https://vercheck.ariga.io\"\n)\n\nfunc noText() string { return \"\" }\n\nfunc checkForUpdate(ctx context.Context) func() string {\n\tversion := cmdapi.Version()\n\t// Users may skip update checking behavior.\n\tif v := os.Getenv(envNoUpdate); v != \"\" {\n\t\treturn noText\n\t}\n\t// Skip if the current binary version isn't set (dev mode).\n\tif !semver.IsValid(version) {\n\t\treturn noText\n\t}\n\tendpoint := vercheckEndpoint(ctx)\n\tvc := vercheck.New(endpoint)\n\tif isatty.IsTerminal(os.Stdout.Fd()) {\n\t\treturn bgCheck(ctx, version, vc)\n\t}\n\treturn func() string {\n\t\tmsg, _ := runCheck(ctx, vc, version)\n\t\treturn msg\n\t}\n}\n\n// bgCheck checks for version updates and security advisories for Atlas in the background.\nfunc bgCheck(ctx context.Context, version string, vc *vercheck.VerChecker) func() string {\n\tdone := make(chan struct{})\n\tvar message string\n\tgo func() {\n\t\tdefer close(done)\n\t\tmsg, err := runCheck(ctx, vc, version)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tmessage = msg\n\t}()\n\treturn func() string {\n\t\tselect {\n\t\tcase <-done:\n\t\tcase <-time.After(time.Millisecond * 500):\n\t\t}\n\t\treturn message\n\t}\n}\n\nfunc runCheck(ctx context.Context, vc *vercheck.VerChecker, version string) (string, error) {\n\tpayload, err := vc.Check(ctx, version)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tvar b bytes.Buffer\n\tif err := vercheck.Notify.Execute(&b, payload); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn b.String(), nil\n}\n"
  },
  {
    "path": "cmd/atlas/main_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"time\"\n\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdlog\"\n\t\"ariga.io/atlas/cmd/atlas/internal/cmdstate\"\n)\n\nfunc extendContext(ctx context.Context) (context.Context, error) {\n\treturn ctx, nil\n}\n\nfunc vercheckEndpoint(context.Context) string {\n\treturn vercheckURL\n}\n\n// initialize is a no-op for the OSS version.\nfunc initialize(ctx context.Context) (context.Context, func(error)) {\n\treturn ctx, func(err error) {\n\t\tif err == nil {\n\t\t\treturn\n\t\t}\n\t\tconst errorsFileName = \"community_error.json\"\n\t\ttype prompt struct {\n\t\t\tLastSuggested time.Time `json:\"last_suggested\"`\n\t\t}\n\t\tstate := &cmdstate.File[prompt]{Name: errorsFileName}\n\t\tprev, err := state.Read()\n\t\tif err != nil || time.Since(prev.LastSuggested) < 24*time.Hour {\n\t\t\treturn\n\t\t}\n\t\trelease := \"curl -sSf https://atlasgo.sh | sh\"\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\trelease = \"https://release.ariga.io/atlas/atlas-windows-amd64-latest.exe\"\n\t\t}\n\t\tif err := cmdlog.WarnOnce(os.Stderr, cmdlog.ColorCyan(fmt.Sprintf(`You're running the community build of Atlas, which may differ from the official version.\nIf this error persists, try installing the official version as a troubleshooting step:\n\n  %s\n\nMore installation options: https://atlasgo.io/docs#installation\n`, release))); err == nil {\n\t\t\tprev.LastSuggested = time.Now()\n\t\t\t_ = state.Write(prev)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module ariga.io/atlas\n\ngo 1.24.13\n\nrequire (\n\tgithub.com/DATA-DOG/go-sqlmock v1.5.0\n\tgithub.com/bmatcuk/doublestar v1.3.4\n\tgithub.com/go-openapi/inflect v0.19.0\n\tgithub.com/hashicorp/hcl/v2 v2.13.0\n\tgithub.com/mattn/go-sqlite3 v1.14.28\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/zclconf/go-cty v1.14.4\n\tgithub.com/zclconf/go-cty-yaml v1.1.0\n\tgolang.org/x/mod v0.26.0\n\tgopkg.in/yaml.v3 v3.0.1\n)\n\nrequire (\n\tgithub.com/agext/levenshtein v1.2.1 // indirect\n\tgithub.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect\n\tgithub.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/kr/pretty v0.2.1 // indirect\n\tgithub.com/kr/text v0.2.0 // indirect\n\tgithub.com/kylelemons/godebug v1.1.0 // indirect\n\tgithub.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgolang.org/x/text v0.28.0 // indirect\n\tgopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=\ngithub.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=\ngithub.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=\ngithub.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=\ngithub.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=\ngithub.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=\ngithub.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=\ngithub.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=\ngithub.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=\ngithub.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=\ngithub.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc=\ngithub.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=\ngithub.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=\ngithub.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=\ngithub.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=\ngithub.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=\ngithub.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=\ngithub.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=\ngithub.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=\ngithub.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0=\ngithub.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=\ngolang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=\ngolang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=\ngolang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=\ngolang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "internal/ci/ci_dialect.tmpl",
    "content": "# # # # # # # # # # # # # # # #\n# CODE GENERATED - DO NOT EDIT\n# # # # # # # # # # # # # # # #\nname: CI - Dialect Tests{{ with $.Flavor }} - {{ . }} Edition{{ end }}\non:\n  workflow_call:\n{{ .Concurrency }}\n{{- if .GlobalEnv }}\nenv:\n{{- end }}\n{{- range .GlobalEnv }}\n  {{ .K }}: {{ .V }}\n{{- end }}\njobs:\n{{- range $.Jobs }}\n  integration-{{ .Version }}:\n    runs-on: {{ or .Runner $.Runner }}\n    {{- if .Image }}\n    services:\n      {{ .Version }}:\n        image: {{ .Image }}\n        {{- with .Credentials }}\n        credentials:\n          username: {{ print `${{ ` .Username ` }}` }}\n          password: {{ print `${{ ` .Password ` }}` }}\n        {{- end }}\n        {{- with .Env }}\n        env:\n          {{- range . }}\n          {{ . }}{{ end }}\n        {{- end }}\n        {{- with .Ports }}\n        ports:\n          {{- range . }}\n          - {{ . }}{{ end }}\n        {{- end }}\n        {{- with .Volumes }}\n        volumes:\n          {{- range . }}\n          - {{ . }}{{ end }}\n        {{- end }}\n        {{- with .Options }}\n        options: >-\n          {{- range . }}\n          {{ . }}{{ end }}\n        {{- end }}\n    {{- end }}\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      {{- with .Steps }}\n      {{- range . }}\n      - name: {{ .Name }}\n        {{- with .Run }}\n        run: |\n          {{- range $line := split . \"\\n\" }}\n          {{ $line | trim }}\n          {{- end }}\n        {{- end }}\n        {{- with .Action }}\n        uses: {{ . }}\n        {{- end }}\n        {{- with .With }}\n        with:\n          {{- range . }}\n          {{ . }}{{ end }}\n        {{- end }}\n      {{- end }}\n      {{- end }}\n      - name: Run integration tests for {{ .Version }}\n        working-directory: internal/integration\n        run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race -count=2 -v -run=\"{{ .Regex }}\" -version=\"{{ .Version }}\" -timeout 15m ./...\n        {{- with .Env }}\n        env:\n          {{- range . }}\n          {{ . }}{{ end }}\n        {{- end }}\n{{- end }}\n"
  },
  {
    "path": "internal/ci/ci_go.tmpl",
    "content": "# # # # # # # # # # # # # # # #\n# CODE GENERATED - DO NOT EDIT\n# # # # # # # # # # # # # # # #\nname: CI - General{{ with $.Flavor }} - {{ . }} Edition{{ end }}\non:\n  pull_request:\n    paths-ignore:\n      - 'doc/**'\n      - 'ops/**'\n  push:\n    branches:\n      - master\n    paths-ignore:\n      - 'doc/**'\n      - 'ops/**'\n{{ .Concurrency }}\n{{- if .GlobalEnv }}\nenv:\n{{- end }}\n{{- range .GlobalEnv }}\n  {{ .K }}: {{ .V }}\n{{- end }}\njobs:\n  lint:\n    runs-on: {{ $.Runner }}\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      {{- with .SharedSteps }}\n      {{- range . }}\n      - name: {{ .Name }}\n        uses: {{ .Action }}\n        {{- with .With }}\n        with:\n          {{- range . }}\n          {{ . }}{{ end }}\n        {{- end }}\n      {{- end }}\n      {{- end }}\n      - name: Run linters\n        uses: golangci/golangci-lint-action@v6\n        with:\n          args: --verbose\n\n  generate-cmp:\n    runs-on: {{ $.Runner }}\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      {{- with .SharedSteps }}\n      {{- range . }}\n      - name: {{ .Name }}\n        uses: {{ .Action }}\n        {{- with .With }}\n        with:\n          {{- range . }}\n          {{ . }}{{ end }}\n        {{- end }}\n      {{- end }}\n      {{- end }}\n      - name: Install stringer\n        run: go install golang.org/x/tools/cmd/stringer@latest\n      - name: run \"go generate ./...\"\n        run: go generate ./...\n      - name: go generate cmd/atlas\n        working-directory: cmd/atlas\n        run: go generate ./...\n      - name: Verify generated files are checked-in properly\n        run: |\n          status=$(git status --porcelain | grep -v \"go.\\(sum\\|mod\\)\" | cat)\n          if [ -n \"$status\" ]; then\n            echo \"you need to run 'go generate ./...' and commit the changes\"\n            echo \"$status\"\n            exit 1\n          fi\n  unit:\n    runs-on: {{ $.Runner }}\n    strategy:\n      matrix:\n        go: {{ with $.GoVersions }}{{ . }}{{ end }}\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version: {{ \"${{ matrix.go }}\" }}\n      {{- with .SharedSteps }}\n      {{- range . }}\n      - name: {{ .Name }}\n        uses: {{ .Action }}\n        {{- with .With }}\n        with:\n          {{- range . }}\n          {{ . }}{{ end }}\n        {{- end }}\n      {{- end }}\n      {{- end }}\n      - name: Run sql tests\n        run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race ./...\n        working-directory: sql\n      - name: Run schemahcl tests\n        run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race ./...\n        working-directory: schemahcl\n\n  cli:\n    runs-on: {{ $.Runner }}\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      {{- with .SharedSteps }}\n      {{- range . }}\n      - name: {{ .Name }}\n        uses: {{ .Action }}\n        {{- with .With }}\n        with:\n          {{- range . }}\n          {{ . }}{{ end }}\n        {{- end }}\n      {{- end }}\n      {{- end }}\n      - name: Run cli tests\n        run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race ./...\n        working-directory: cmd/atlas\n\n  integration:\n    runs-on: {{ $.Runner }}\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      {{- with .SharedSteps }}\n      {{- range . }}\n      - name: {{ .Name }}\n        uses: {{ .Action }}\n        {{- with .With }}\n        with:\n          {{- range . }}\n          {{ . }}{{ end }}\n        {{- end }}\n      {{- end }}\n      {{- end }}\n      - name: Run integration tests for HCL\n        working-directory: internal/integration/hclsqlspec\n        run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race -count=2 -v ./...\n\n  dialect-integration:\n    needs: [lint, generate-cmp, unit, cli, integration]\n    uses: ./.github/workflows/ci-dialect_{{ $.Suffix }}.yaml\n    secrets: inherit\n"
  },
  {
    "path": "internal/ci/ci_revisions.tmpl",
    "content": "# # # # # # # # # # # # # # # #\n# CODE GENERATED - DO NOT EDIT\n# # # # # # # # # # # # # # # #\nname: CI - Revisions{{ with $.Flavor }} - {{ . }} Edition{{ end }}\non:\n  pull_request:\n    paths:\n      - 'cmd/atlas/internal/migrate/ent/**'\n  push:\n    branches:\n      - master\n    paths:\n      - 'cmd/atlas/internal/migrate/ent/**'\n{{ .Concurrency }}\njobs:\n  revisions:\n    runs-on: {{ $.Runner }}\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: actions/setup-go@v5\n        with:\n          go-version-file: cmd/atlas/go.mod\n      {{- with .SharedSteps }}\n      {{- range . }}\n      - name: {{ .Name }}\n        uses: {{ .Action }}\n        {{- with .With }}\n        with:\n          {{- range . }}\n          {{ . }}{{ end }}\n        {{- end }}\n      {{- end }}\n      {{- end }}\n      - name: Checkout origin/master\n        run: git checkout origin/master\n      - name: Create revisions from master\n        run: go run {{ with $.Tags }}-tags={{ . }} {{ end }}. migrate apply --dir file://internal/cmdapi/testdata/sqlite --url sqlite://db?_fk=1\n        working-directory: cmd/atlas\n      - name: Checkout previous HEAD\n        run: git checkout -\n      - name: Migrate revisions table to HEAD\n        run: go run {{ with $.Tags }}-tags={{ . }} {{ end }}. migrate apply --dir file://internal/cmdapi/testdata/sqlite --url sqlite://db?_fk=1\n        working-directory: cmd/atlas"
  },
  {
    "path": "internal/ci/cockroach/Dockerfile.tmpl",
    "content": "FROM cockroachdb/cockroach:{{ .Version}}\n\nEXPOSE 8080\nEXPOSE 26257\n\nENTRYPOINT [\"/cockroach/cockroach\", \"start-single-node\", \"--insecure\"]"
  },
  {
    "path": "internal/ci/cockroach/main.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage main\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"os\"\n\t\"text/template\"\n)\n\ntype params struct {\n\tVersion string\n}\n\n//go:embed Dockerfile.tmpl\nvar dockerTmpl string\n\nfunc main() {\n\tif len(os.Args) < 2 {\n\t\tfmt.Println(\"please supply version as argument e.g. 'v22.1.0'\")\n\t\tos.Exit(1)\n\t}\n\n\tp := params{\n\t\tVersion: os.Args[1],\n\t}\n\tt, err := template.New(\"docker\").Parse(dockerTmpl)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\terr = t.Execute(os.Stdout, p)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "internal/ci/jobs_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage main\n\n//go:generate go run . -flavor Community -suffix oss\n\nfunc init() {\n\tdata.GoVersions = goVersions{\"1.22\"}\n\tdata.GlobalEnv = []struct{ K, V string }{\n\t\t{K: \"ATLAS_NO_UPGRADE_SUGGESTIONS\", V: \"1\"},\n\t}\n\tdata.Jobs = append(jobs,\n\t\tJob{\n\t\t\tVersion: \"tidb5\",\n\t\t\tImage:   \"pingcap/tidb:v5.4.0\",\n\t\t\tRegex:   \"TiDB\",\n\t\t\tPorts:   []string{\"4309:4000\"},\n\t\t},\n\t\tJob{\n\t\t\tVersion: \"tidb6\",\n\t\t\tImage:   \"pingcap/tidb:v6.0.0\",\n\t\t\tRegex:   \"TiDB\",\n\t\t\tPorts:   []string{\"4310:4000\"},\n\t\t},\n\t\tJob{\n\t\t\tVersion: \"cockroach\",\n\t\t\tImage:   \"ghcr.io/ariga/cockroachdb-single-node:v21.2.11\",\n\t\t\tRegex:   \"Cockroach\",\n\t\t\tPorts:   []string{\"26257:26257\"},\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "internal/ci/main.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage main\n\nimport (\n\t\"bytes\"\n\t\"embed\"\n\t_ \"embed\"\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/template\"\n)\n\ntype (\n\t// Step defines a step to run.\n\tStep struct {\n\t\tName   string\n\t\tAction string\n\t\tRun    string\n\t\tWith   []string\n\t}\n\t// Credentials is used to pull images from a private registry.\n\tCredentials struct {\n\t\tUsername string\n\t\tPassword string\n\t}\n\t// Job defines an integration job to run.\n\tJob struct {\n\t\tRunner      string       // runner to use\n\t\tVersion     string       // version to test (passed to go test as flag which database dialect/version)\n\t\tImage       string       // name of service\n\t\tCredentials *Credentials // credentials to pull the image\n\t\tRegex       string       // run regex\n\t\tEnv         []string     // env of service\n\t\tPorts       []string     // port mappings\n\t\tVolumes     []string     // volume mappings\n\t\tOptions     []string     // other options\n\t\tSteps       []Step       // extra steps to run\n\t}\n)\n\nvar (\n\t//go:embed *.tmpl\n\ttplFS embed.FS\n\ttpl   = template.Must(template.New(\"\").\n\t\tFuncs(template.FuncMap{\n\t\t\t\"split\": strings.Split,\n\t\t\t\"trim\":  strings.TrimSpace,\n\t\t}).\n\t\tParseFS(tplFS, \"*.tmpl\"))\n\n\tmysqlOptions = []string{\n\t\t`--health-cmd \"mysqladmin ping -ppass\"`,\n\t\t`--health-interval 10s`,\n\t\t`--health-start-period 10s`,\n\t\t`--health-timeout 5s`,\n\t\t`--health-retries 10`,\n\t}\n\tmysqlEnv = []string{\n\t\t\"MYSQL_DATABASE: test\",\n\t\t\"MYSQL_ROOT_PASSWORD: pass\",\n\t}\n\tpgOptions = []string{\n\t\t\"--health-cmd pg_isready\",\n\t\t\"--health-interval 10s\",\n\t\t\"--health-timeout 5s\",\n\t\t\"--health-retries 5\",\n\t}\n\tpgEnv = []string{\n\t\t\"POSTGRES_DB: test\",\n\t\t\"POSTGRES_PASSWORD: pass\",\n\t}\n\tjobs = []Job{\n\t\t{\n\t\t\tVersion: \"mysql56\",\n\t\t\tImage:   \"mysql:5.6.35\",\n\t\t\tRegex:   \"MySQL\",\n\t\t\tEnv:     mysqlEnv,\n\t\t\tPorts:   []string{\"3306:3306\"},\n\t\t\tOptions: mysqlOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"mysql57\",\n\t\t\tImage:   \"mysql:5.7.26\",\n\t\t\tRegex:   \"MySQL\",\n\t\t\tEnv:     mysqlEnv,\n\t\t\tPorts:   []string{\"3307:3306\"},\n\t\t\tOptions: mysqlOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"mysql8\",\n\t\t\tImage:   \"mysql:8\",\n\t\t\tRegex:   \"MySQL\",\n\t\t\tEnv:     mysqlEnv,\n\t\t\tPorts:   []string{\"3308:3306\"},\n\t\t\tOptions: mysqlOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"maria107\",\n\t\t\tImage:   \"mariadb:10.7\",\n\t\t\tRegex:   \"MySQL\",\n\t\t\tEnv:     mysqlEnv,\n\t\t\tPorts:   []string{\"4306:3306\"},\n\t\t\tOptions: mysqlOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"maria102\",\n\t\t\tImage:   \"mariadb:10.2.32\",\n\t\t\tRegex:   \"MySQL\",\n\t\t\tEnv:     mysqlEnv,\n\t\t\tPorts:   []string{\"4307:3306\"},\n\t\t\tOptions: mysqlOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"maria103\",\n\t\t\tImage:   \"mariadb:10.3.13\",\n\t\t\tRegex:   \"MySQL\",\n\t\t\tEnv:     mysqlEnv,\n\t\t\tPorts:   []string{\"4308:3306\"},\n\t\t\tOptions: mysqlOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"postgres-ext-postgis\",\n\t\t\tImage:   \"postgis/postgis:latest\",\n\t\t\tRegex:   \"Postgres\",\n\t\t\tEnv:     pgEnv,\n\t\t\tPorts:   []string{\"5429:5432\"},\n\t\t\tOptions: pgOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"postgres10\",\n\t\t\tImage:   \"postgres:10\",\n\t\t\tRegex:   \"Postgres\",\n\t\t\tEnv:     pgEnv,\n\t\t\tPorts:   []string{\"5430:5432\"},\n\t\t\tOptions: pgOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"postgres11\",\n\t\t\tImage:   \"postgres:11\",\n\t\t\tRegex:   \"Postgres\",\n\t\t\tEnv:     pgEnv,\n\t\t\tPorts:   []string{\"5431:5432\"},\n\t\t\tOptions: pgOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"postgres12\",\n\t\t\tImage:   \"postgres:12.3\",\n\t\t\tRegex:   \"Postgres\",\n\t\t\tEnv:     pgEnv,\n\t\t\tPorts:   []string{\"5432:5432\"},\n\t\t\tOptions: pgOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"postgres13\",\n\t\t\tImage:   \"postgres:13.1\",\n\t\t\tRegex:   \"Postgres\",\n\t\t\tEnv:     pgEnv,\n\t\t\tPorts:   []string{\"5433:5432\"},\n\t\t\tOptions: pgOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"postgres14\",\n\t\t\tImage:   \"postgres:14\",\n\t\t\tRegex:   \"Postgres\",\n\t\t\tEnv:     pgEnv,\n\t\t\tPorts:   []string{\"5434:5432\"},\n\t\t\tOptions: pgOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"postgres15\",\n\t\t\tImage:   \"postgres:15\",\n\t\t\tRegex:   \"Postgres\",\n\t\t\tEnv:     pgEnv,\n\t\t\tPorts:   []string{\"5435:5432\"},\n\t\t\tOptions: pgOptions,\n\t\t},\n\t\t{\n\t\t\tVersion: \"sqlite\",\n\t\t\tRegex:   \"SQLite.*\",\n\t\t},\n\t}\n)\n\ntype (\n\tgoVersions  []string\n\tconcurrency struct {\n\t\tgroup  string\n\t\tcancel bool\n\t}\n)\n\nvar data = struct {\n\tJobs                         []Job\n\tFlavor, Tags, Runner, Suffix string\n\tGoVersions                   goVersions\n\tConcurrency                  concurrency\n\tSharedSteps                  []Step\n\tGlobalEnv                    []struct{ K, V string }\n}{\n\tConcurrency: concurrency{\n\t\tgroup:  \"${{ github.workflow }}-${{ github.head_ref || github.run_id }}\",\n\t\tcancel: true,\n\t},\n}\n\nfunc main() {\n\tflag.StringVar(&data.Flavor, \"flavor\", \"\", \"\")\n\tflag.StringVar(&data.Tags, \"tags\", \"\", \"\")\n\tflag.StringVar(&data.Runner, \"runner\", \"ubuntu-latest\", \"\")\n\tflag.StringVar(&data.Suffix, \"suffix\", \"\", \"\")\n\tflag.Parse()\n\tfor _, n := range []string{\"dialect\", \"go\", \"revisions\"} {\n\t\tvar (\n\t\t\tbuf bytes.Buffer\n\t\t\tg   = data.Concurrency.group\n\t\t)\n\t\tif n == \"dialect\" {\n\t\t\t// Dialect jobs are running after go jobs, putting them in the same concurrency group crates deadlock.\n\t\t\tdata.Concurrency.group = fmt.Sprintf(\"%s-dialect\", g)\n\t\t}\n\t\tif err := tpl.ExecuteTemplate(&buf, fmt.Sprintf(\"ci_%s.tmpl\", n), data); err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t\tdata.Concurrency.group = g\n\t\terr := os.WriteFile(filepath.Clean(fmt.Sprintf(\"../../.github/workflows/ci-%s_%s.yaml\", n, data.Suffix)), buf.Bytes(), 0600)\n\t\tif err != nil {\n\t\t\tlog.Fatalln(err)\n\t\t}\n\t}\n}\n\nfunc (v goVersions) String() (s string) {\n\tfor i := range v {\n\t\tv[i] = strconv.Quote(v[i])\n\t}\n\treturn fmt.Sprintf(\"[ %s ]\", strings.Join(v, \", \"))\n}\n\nfunc (c concurrency) String() (s string) {\n\treturn fmt.Sprintf(\"concurrency:\\n  group: %s\\n  cancel-in-progress: %t\", c.group, c.cancel)\n}\n"
  },
  {
    "path": "internal/integration/README.md",
    "content": "### This directory contains all integration tests for Atlas.\n\nThe provided `docker-compose.yaml` file contains images for each database the integration tests are run on. You can\nstart them by calling:\n\n```shell\ndocker-compose --project-name atlas-integration up -d\n```\n\nThe whole integration suite is then run by executing within this directory: \n\n```shell\ngo test ./...\n```\n\n#### Selectively running tests\n\nRunning all integration tests (and keeping all database containers up all the time) consumes time and resources (and\npower). You can execute only some of the tests by using the `-run` and `-dialect` flags:\n\nThe below examples don't require for you to have all docker containers running, instead only the ones used in the tests\nhave to be up.\n\nConsider the following test in `mysql_test.go`:\n\n```go\nfunc TestMySQL_Executor(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\ttestExecutor(t)\n\t})\n}\n```\n\nIf you'd wanted to run that test only for mysql56, simply pass its full name into the `-run` flag:\n\n```shell\n# Run TestMySQL_Executor for all mysql versions\ngo test -run='MySQL_Executor' ./... \n\n# Run TestMySQL_Executor for mysql 5.6 only\ngo test -run='MySQL_Executor/mysql56' ./...\n```\n\nIf you'd like to run the above for Postgres 10, change the name respectively:\n\n```shell\n# Run TestPostgres_Executor for all postgres versions\ngo test -run='Postgres_Executor' ./... \n\n# Run TestPostgres_Executor for postgres 10 only\ngo test -run='Postgres_Executor/postgres10' ./...\n```\n\nIf you want to run all tests for one specific dialect, like only TiDB 5, you can use the `-dialect` flag:\n\n```shell\ngo test -run='TiDB' -dialect='tidb5' ./...\n```"
  },
  {
    "path": "internal/integration/cockroach_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage integration\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/postgres\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t_ \"github.com/lib/pq\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype crdbTest struct {\n\t*testing.T\n\tdb      *sql.DB\n\tdrv     migrate.Driver\n\trrw     migrate.RevisionReadWriter\n\tversion string\n\tport    int\n\tonce    sync.Once\n}\n\nvar crdbTests = map[string]*crdbTest{\n\t\"cockroach\": {port: 26257},\n}\n\nfunc crdbRun(t *testing.T, fn func(*crdbTest)) {\n\tfor version, tt := range crdbTests {\n\t\tif flagVersion == \"\" || flagVersion == version {\n\t\t\tt.Run(version, func(t *testing.T) {\n\t\t\t\ttt.once.Do(func() {\n\t\t\t\t\tvar err error\n\t\t\t\t\ttt.version = version\n\t\t\t\t\ttt.rrw = &rrw{}\n\t\t\t\t\ttt.db, err = sql.Open(\"postgres\", fmt.Sprintf(\"host=localhost port=%d user=root dbname=defaultdb password=pass sslmode=disable\", tt.port))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Fatalln(err)\n\t\t\t\t\t}\n\t\t\t\t\tdbs = append(dbs, tt.db) // close connection after all tests have been run\n\t\t\t\t\ttt.drv, err = postgres.Open(tt.db)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Fatalln(err)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\ttt := &crdbTest{T: t, db: tt.db, drv: tt.drv, version: version, port: tt.port, rrw: tt.rrw}\n\t\t\t\tfn(tt)\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc TestCockroach_Executor(t *testing.T) {\n\tcrdbRun(t, func(t *crdbTest) {\n\t\ttestExecutor(t)\n\t})\n}\n\nfunc TestCockroach_AddDropTable(t *testing.T) {\n\tcrdbRun(t, func(t *crdbTest) {\n\t\ttestAddDrop(t)\n\t})\n}\n\nfunc TestCockroach_Relation(t *testing.T) {\n\tcrdbRun(t, func(t *crdbTest) {\n\t\ttestRelation(t)\n\t})\n}\n\nfunc TestCockroach_AddIndexedColumns(t *testing.T) {\n\tcrdbRun(t, func(t *crdbTest) {\n\t\ts := &schema.Schema{\n\t\t\tName: \"public\",\n\t\t}\n\t\tusersT := &schema.Table{\n\t\t\tName:    \"users\",\n\t\t\tSchema:  s,\n\t\t\tColumns: []*schema.Column{{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}, Attrs: []schema.Attr{&postgres.Identity{}}}},\n\t\t}\n\t\tusersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tt.dropTables(usersT.Name)\n\t\tusersT.Columns = append(usersT.Columns, &schema.Column{\n\t\t\tName:    \"a\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t}, &schema.Column{\n\t\t\tName:    \"b\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t}, &schema.Column{\n\t\t\tName:    \"c\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t})\n\t\tparts := usersT.Columns[len(usersT.Columns)-3:]\n\t\tusersT.Indexes = append(usersT.Indexes, &schema.Index{\n\t\t\tUnique: true,\n\t\t\tName:   \"a_b_c_unique\",\n\t\t\tParts:  []*schema.IndexPart{{C: parts[0]}, {C: parts[1]}, {C: parts[2]}},\n\t\t})\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.NotEmpty(t, changes, \"usersT contains 3 new columns and 1 new index\")\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\n\t\t// Dropping a column involves in a multi-column\n\t\t// index causes the index to be dropped as well.\n\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, t.loadUsers())\n\t\tusersT = t.loadUsers()\n\t\t_, ok := usersT.Index(\"a_b_c_unique\")\n\t\trequire.False(t, ok)\n\t})\n}\n\nfunc TestCockroach_AddColumns(t *testing.T) {\n\tcrdbRun(t, func(t *crdbTest) {\n\t\tusersT := t.users()\n\t\tt.dropTables(usersT.Name)\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tusersT.Columns = append(\n\t\t\tusersT.Columns,\n\t\t\t&schema.Column{Name: \"a\", Type: &schema.ColumnType{Type: &schema.BinaryType{T: \"bytea\"}}},\n\t\t\t&schema.Column{Name: \"b\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"double precision\", Precision: 10}}, Default: &schema.Literal{V: \"10.1\"}},\n\t\t\t&schema.Column{Name: \"c\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"character\"}}, Default: &schema.Literal{V: \"'y'\"}},\n\t\t\t&schema.Column{Name: \"d\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 10, Scale: 2}}, Default: &schema.Literal{V: \"0.99\"}},\n\t\t\t&schema.Column{Name: \"e\", Type: &schema.ColumnType{Type: &schema.JSONType{T: \"json\"}}, Default: &schema.Literal{V: \"'{}'\"}},\n\t\t\t&schema.Column{Name: \"f\", Type: &schema.ColumnType{Type: &schema.JSONType{T: \"jsonb\"}}, Default: &schema.Literal{V: \"'1'\"}},\n\t\t\t&schema.Column{Name: \"g\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"float\", Precision: 10}}, Default: &schema.Literal{V: \"'1'\"}},\n\t\t\t&schema.Column{Name: \"h\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"float\", Precision: 30}}, Default: &schema.Literal{V: \"'1'\"}},\n\t\t\t&schema.Column{Name: \"i\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"float\", Precision: 53}}, Default: &schema.Literal{V: \"1\"}},\n\t\t\t&schema.Column{Name: \"j\", Type: &schema.ColumnType{Type: &postgres.SerialType{T: \"serial\"}}},\n\t\t\t&schema.Column{Name: \"m\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}, Null: true}, Default: &schema.Literal{V: \"false\"}},\n\t\t\t&schema.Column{Name: \"n\", Type: &schema.ColumnType{Type: &schema.SpatialType{T: \"geometry\"}, Null: true}, Default: &schema.Literal{V: \"'POINT(1 2)'\"}},\n\t\t\t&schema.Column{Name: \"o\", Type: &schema.ColumnType{Type: &schema.SpatialType{T: \"geometry\"}, Null: true}, Default: &schema.Literal{V: \"'LINESTRING(0 0, 1440 900)'\"}},\n\t\t\t&schema.Column{Name: \"q\", Type: &schema.ColumnType{Type: &postgres.ArrayType{Type: &schema.StringType{T: \"text\"}, T: \"text[]\"}, Null: true}, Default: &schema.Literal{V: \"'{}'\"}},\n\t\t)\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 14)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestCockroach_ColumnInt(t *testing.T) {\n\tctx := context.Background()\n\trun := func(t *testing.T, change func(*schema.Column)) {\n\t\tcrdbRun(t, func(t *crdbTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}}},\n\t\t\t}\n\t\t\terr := t.drv.ApplyChanges(ctx, []schema.Change{&schema.AddTable{T: usersT}})\n\t\t\trequire.NoError(t, err)\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tchange(usersT.Columns[0])\n\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 1)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t}\n\n\tt.Run(\"ChangeNull\", func(t *testing.T) {\n\t\trun(t, func(c *schema.Column) {\n\t\t\tc.Type.Null = true\n\t\t})\n\t})\n\n\tt.Run(\"ChangeDefault\", func(t *testing.T) {\n\t\trun(t, func(c *schema.Column) {\n\t\t\tc.Default = &schema.RawExpr{X: \"0\"}\n\t\t})\n\t})\n}\n\nfunc TestCockroach_ColumnArray(t *testing.T) {\n\tcrdbRun(t, func(t *crdbTest) {\n\t\tusersT := t.users()\n\t\tt.dropTables(usersT.Name)\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\n\t\t// Add column.\n\t\tusersT.Columns = append(\n\t\t\tusersT.Columns,\n\t\t\t&schema.Column{Name: \"a\", Type: &schema.ColumnType{Raw: \"bigint[]\", Type: &postgres.ArrayType{Type: &schema.IntegerType{T: \"bigint\"}, T: \"bigint[]\"}}, Default: &schema.Literal{V: \"'{1}'\"}},\n\t\t)\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 1)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\n\t\t// Check default.\n\t\tusersT.Columns[2].Default = &schema.RawExpr{X: \"ARRAY[1]\"}\n\t\tensureNoChange(t, usersT)\n\n\t\t// Change default.\n\t\tusersT.Columns[2].Default = &schema.RawExpr{X: \"ARRAY[1,2]\"}\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 1)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestCockroach_Enums(t *testing.T) {\n\tcrdbRun(t, func(t *crdbTest) {\n\t\tctx := context.Background()\n\t\tusersT := &schema.Table{\n\t\t\tName:   \"users\",\n\t\t\tSchema: t.realm().Schemas[0],\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"state\", Type: &schema.ColumnType{Type: &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\"}}}},\n\t\t\t},\n\t\t}\n\t\tt.Cleanup(func() {\n\t\t\t_, err := t.drv.ExecContext(ctx, \"DROP TYPE IF EXISTS state, day\")\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\t// Create table with an enum column.\n\t\terr := t.drv.ApplyChanges(ctx, []schema.Change{\n\t\t\t&schema.AddObject{O: &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\"}, Schema: usersT.Schema}},\n\t\t\t&schema.AddTable{T: usersT},\n\t\t})\n\t\trequire.NoError(t, err, \"create a new table with an enum column\")\n\t\tt.dropTables(usersT.Name)\n\t\tensureNoChange(t, usersT)\n\n\t\t// Add another enum column.\n\t\tusersT.Columns = append(\n\t\t\tusersT.Columns,\n\t\t\t&schema.Column{Name: \"day\", Type: &schema.ColumnType{Type: &schema.EnumType{T: \"day\", Values: []string{\"sunday\", \"monday\"}}}},\n\t\t)\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 1)\n\t\terr = t.drv.ApplyChanges(ctx, []schema.Change{\n\t\t\t&schema.AddObject{O: &schema.EnumType{T: \"day\", Values: []string{\"sunday\", \"monday\"}, Schema: usersT.Schema}},\n\t\t\t&schema.ModifyTable{T: usersT, Changes: changes},\n\t\t})\n\t\trequire.NoError(t, err, \"add a new enum column to existing table\")\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestCockroach_HCL(t *testing.T) {\n\tfull := `\nschema \"public\" {\n}\ntable \"users\" {\n\tschema = schema.public\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tprimary_key {\n\t\tcolumns = [table.users.column.id]\n\t}\n}\ntable \"posts\" {\n\tschema = schema.public\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tcolumn \"tags\" {\n\t\ttype = sql(\"text[]\")\n\t}\n\tcolumn \"author_id\" {\n\t\ttype = int\n\t}\n\tforeign_key \"author\" {\n\t\tcolumns = [\n\t\t\ttable.posts.column.author_id,\n\t\t]\n\t\tref_columns = [\n\t\t\ttable.users.column.id,\n\t\t]\n\t}\n\tprimary_key {\n\t\tcolumns = [table.users.column.id]\n\t}\n}\n`\n\tempty := `\nschema \"public\" {\n}\n`\n\tcrdbRun(t, func(t *crdbTest) {\n\t\ttestHCLIntegration(t, full, empty)\n\t})\n}\n\nfunc TestCockroach_HCL_Realm(t *testing.T) {\n\tcrdbRun(t, func(t *crdbTest) {\n\t\tt.dropSchemas(\"second\")\n\t\trealm := t.loadRealm()\n\t\thcl, err := postgres.MarshalHCL(realm)\n\t\trequire.NoError(t, err)\n\t\twa := string(hcl) + `\nschema \"second\" {\n}\n`\n\t\tt.applyRealmHcl(wa)\n\t\trealm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{})\n\t\trequire.NoError(t, err)\n\t\t_, ok := realm.Schema(\"public\")\n\t\trequire.True(t, ok)\n\t\t_, ok = realm.Schema(\"second\")\n\t\trequire.True(t, ok)\n\t})\n}\n\nfunc TestCockroach_CLI(t *testing.T) {\n\th := `\n\t\t\tschema \"public\" {\n\t\t\t}\n\t\t\ttable \"users\" {\n\t\t\t\tschema = schema.public\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = bigint\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [table.users.column.id]\n\t\t\t\t}\n\t\t\t}`\n\tt.Run(\"SchemaInspect\", func(t *testing.T) {\n\t\tcrdbRun(t, func(t *crdbTest) {\n\t\t\ttestCLISchemaInspect(t, h, t.url(\"\"), postgres.EvalHCL, \"-s\", \"public\")\n\t\t})\n\t})\n\tt.Run(\"SchemaApply\", func(t *testing.T) {\n\t\tcrdbRun(t, func(t *crdbTest) {\n\t\t\ttestCLISchemaApply(t, h, t.url(\"\"), \"-s\", \"public\")\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyDryRun\", func(t *testing.T) {\n\t\tcrdbRun(t, func(t *crdbTest) {\n\t\t\ttestCLISchemaApplyDry(t, h, t.url(\"\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyWithVars\", func(t *testing.T) {\n\t\th := `\nvariable \"tenant\" {\n\ttype = string\n}\nschema \"tenant\" {\n\tname = var.tenant\n}\ntable \"users\" {\n\tschema = schema.tenant\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n}\n`\n\t\tcrdbRun(t, func(t *crdbTest) {\n\t\t\ttestCLISchemaApply(t, h, t.url(\"\"), \"--var\", \"tenant=public\", \"-s\", \"public\")\n\t\t})\n\t})\n\tt.Run(\"SchemaDiffRun\", func(t *testing.T) {\n\t\tcrdbRun(t, func(t *crdbTest) {\n\t\t\ttestCLISchemaDiff(t, t.url(\"\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyAutoApprove\", func(t *testing.T) {\n\t\tcrdbRun(t, func(t *crdbTest) {\n\t\t\ttestCLISchemaApplyAutoApprove(t, h, t.url(\"\"), \"-s\", \"public\")\n\t\t})\n\t})\n}\n\nfunc TestCockroach_CLI_MultiSchema(t *testing.T) {\n\th := `\n\t\t\tschema \"public\" {\t\n\t\t\t}\n\t\t\ttable \"users\" {\n\t\t\t\tschema = schema.public\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = bigint\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [table.users.column.id]\n\t\t\t\t}\n\t\t\t}\n\t\t\tschema \"test2\" {\t\n\t\t\t}\n\t\t\ttable \"users\" {\n\t\t\t\tschema = schema.test2\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = bigint\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [table.users.column.id]\n\t\t\t\t}\n\t\t\t}`\n\tt.Run(\"SchemaInspect\", func(t *testing.T) {\n\t\tcrdbRun(t, func(t *crdbTest) {\n\t\t\tt.dropSchemas(\"test2\")\n\t\t\tt.dropTables(\"users\")\n\t\t\ttestCLIMultiSchemaInspect(t, h, t.url(\"\"), []string{\"public\", \"test2\"}, postgres.EvalHCL)\n\t\t})\n\t})\n\tt.Run(\"SchemaApply\", func(t *testing.T) {\n\t\tcrdbRun(t, func(t *crdbTest) {\n\t\t\tt.dropSchemas(\"test2\")\n\t\t\tt.dropTables(\"users\")\n\t\t\ttestCLIMultiSchemaApply(t, h, t.url(\"\"), []string{\"public\", \"test2\"}, postgres.EvalHCL)\n\t\t})\n\t})\n}\n\nfunc TestCockroach_DefaultsHCL(t *testing.T) {\n\tn := \"atlas_defaults\"\n\tcrdbRun(t, func(t *crdbTest) {\n\t\tddl := `\ncreate table atlas_defaults\n(\n\tstring varchar(255) default 'hello_world',\n\tquoted varchar(100) default 'never say \"never\"',\n\ttBit bit(10) default B'10101',\n\tts timestamp default CURRENT_TIMESTAMP,\n\ttstz timestamp with time zone default CURRENT_TIMESTAMP,\n\tnumber int default 42\n)\n`\n\t\tt.dropTables(n)\n\t\t_, err := t.db.Exec(ddl)\n\t\trequire.NoError(t, err)\n\t\trealm := t.loadRealm()\n\t\tspec, err := postgres.MarshalHCL(realm.Schemas[0])\n\t\trequire.NoError(t, err)\n\t\tvar s schema.Schema\n\t\terr = postgres.EvalHCLBytes(spec, &s, nil)\n\t\trequire.NoError(t, err)\n\t\tt.dropTables(n)\n\t\tt.applyHcl(string(spec))\n\t\tensureNoChange(t, realm.Schemas[0].Tables[0])\n\t})\n}\n\nfunc TestCockroach_Sanity(t *testing.T) {\n\tn := \"atlas_types_sanity\"\n\tddl := `\ncreate table atlas_types_sanity\n(\n    \"tBit\"                 bit(10)                     default B'100'                                   null,\n    \"tBitVar\"              bit varying(10)             default B'100'                                   null,\n    \"tBoolean\"             boolean                     default false                                not null,\n    \"tBool\"                bool                        default false                                not null,\n    \"tBytea\"               bytea                       default E'\\\\001'                             not null,\n    \"tCharacter\"           character(10)               default 'atlas'                                  null,\n    \"tChar\"                char(10)                    default 'atlas'                                  null,\n    \"tCharVar\"             character varying(10)       default 'atlas'                                  null,\n    \"tVarChar\"             varchar(10)                 default 'atlas'                                  null,\n    \"tText\"                text                        default 'atlas'                                  null,\n    \"tSmallInt\"            smallint                    default '10'                                     null,\n    \"tInteger\"             integer                     default '10'                                     null,\n    \"tBigInt\"              bigint                      default '10'                                     null,\n    \"tInt\"                 int                         default '10'                                     null,\n    \"tInt2\"                int2                        default '10'                                     null,\n    \"tInt4\"                int4                        default '10'                                     null,\n    \"tInt8\"                int8                        default '10'                                     null,\n    \"tInet\"                inet                        default '127.0.0.1'                              null,\n    \"tGeometry\"            geometry                    default                                          null,\n    \"tDate\"                date                        default current_date                             null,\n    \"tTime\"                time                        default current_time                             null,\n    \"tTimeWTZ\"             time with time zone         default current_time                             null,\n    \"tTimeWOTZ\"            time without time zone      default current_time                             null,\n    \"tTimestamp\"           timestamp                   default now()                                    null,\n    \"tTimestampTZ\"         timestamptz                 default now()                                    null,\n    \"tTimestampWTZ\"        timestamp with time zone    default now()                                    null,\n    \"tTimestampWOTZ\"       timestamp without time zone default now()                                    null,\n    \"tTimestampPrec\"       timestamp(4)                default now()                                    null,\n    \"tDouble\"              double precision            default 0                                        null,\n    \"tReal\"                real                        default 0                                        null,\n    \"tFloat8\"              float8                      default 0                                        null,\n    \"tFloat4\"              float4                      default 0                                        null,\n    \"tNumeric\"             numeric                     default 0                                        null,\n    \"tDecimal\"             decimal                     default 0                                        null,\n    \"tSmallSerial\"         smallserial                                                                      ,\n    \"tSerial\"              serial                                                                           ,\n    \"tBigSerial\"           bigserial                                                                        ,\n    \"tSerial2\"             serial2                                                                          ,\n    \"tSerial4\"             serial4                                                                          ,\n    \"tSerial8\"             serial8                                                                          ,\n    \"tArray\"               text[10]                     default '{}'                                    null,\n    \"tJSON\"                json                         default '{\"key\":\"value\"}'                       null,\n    \"tJSONB\"               jsonb                        default '{\"key\":\"value\"}'                       null,\n    \"tUUID\"                uuid                         default  'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11' null,\n    \"tInterval\"            interval                     default '4 hours'                               null\n);\n`\n\tcrdbRun(t, func(t *crdbTest) {\n\t\tt.dropTables(n)\n\t\t_, err := t.db.Exec(ddl)\n\t\trequire.NoError(t, err)\n\t\trealm := t.loadRealm()\n\t\trequire.Len(t, realm.Schemas, 1)\n\t\tts, ok := realm.Schemas[0].Table(n)\n\t\trequire.True(t, ok)\n\t\texpected := schema.Table{\n\t\t\tName:   n,\n\t\t\tSchema: realm.Schemas[0],\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBit\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &postgres.BitType{T: \"bit\", Len: 10}, Raw: \"bit\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"B'100'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBitVar\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &postgres.BitType{T: \"bit varying\", Len: 10}, Raw: \"bit varying\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"B'100'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBoolean\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}, Raw: \"boolean\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{V: \"false\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBool\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}, Raw: \"boolean\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{V: \"false\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBytea\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.BinaryType{T: \"bytea\"}, Raw: \"bytea\", Null: false},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"'\\\\x01':::BYTES\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tCharacter\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.StringType{T: \"character\", Size: 10}, Raw: \"character\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"'atlas':::STRING\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tChar\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.StringType{T: \"character\", Size: 10}, Raw: \"character\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"'atlas':::STRING\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tCharVar\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.StringType{T: \"character varying\", Size: 10}, Raw: \"character varying\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"'atlas':::STRING\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tVarChar\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.StringType{T: \"character varying\", Size: 10}, Raw: \"character varying\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"'atlas':::STRING\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tText\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Raw: \"text\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"'atlas':::STRING\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tSmallInt\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"smallint\"}, Raw: \"smallint\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"10:::INT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInteger\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}, Raw: \"bigint\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"10:::INT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBigInt\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}, Raw: \"bigint\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"10:::INT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInt\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}, Raw: \"bigint\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"10:::INT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInt2\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"smallint\"}, Raw: \"smallint\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"10:::INT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInt4\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Raw: \"integer\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"10:::INT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInt8\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}, Raw: \"bigint\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"10:::INT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInet\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &postgres.NetworkType{T: \"inet\"}, Raw: \"inet\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"'127.0.0.1':::INET\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tGeometry\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"geometry\"}, Raw: \"geometry\", Null: true},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tDate\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"date\"}, Raw: \"date\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"current_date()\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTime\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"time without time zone\", Precision: intp(6)}, Raw: \"time without time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"current_time():::TIME\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimeWTZ\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"time with time zone\", Precision: intp(6)}, Raw: \"time with time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"current_time():::TIMETZ\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimeWOTZ\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"time without time zone\", Precision: intp(6)}, Raw: \"time without time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"current_time():::TIME\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimestamp\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp without time zone\", Precision: intp(6)}, Raw: \"timestamp without time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now():::TIMESTAMP\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimestampTZ\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp with time zone\", Precision: intp(6)}, Raw: \"timestamp with time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now():::TIMESTAMPTZ\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimestampWTZ\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp with time zone\", Precision: intp(6)}, Raw: \"timestamp with time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now():::TIMESTAMPTZ\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimestampWOTZ\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp without time zone\", Precision: intp(6)}, Raw: \"timestamp without time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now():::TIMESTAMP\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimestampPrec\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp without time zone\", Precision: intp(4)}, Raw: \"timestamp without time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now():::TIMESTAMP\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tDouble\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.FloatType{T: \"double precision\", Precision: 53}, Raw: \"double precision\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"0.0:::FLOAT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tReal\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.FloatType{T: \"real\", Precision: 24}, Raw: \"real\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"0.0:::FLOAT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tFloat8\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.FloatType{T: \"double precision\", Precision: 53}, Raw: \"double precision\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"0.0:::FLOAT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tFloat4\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.FloatType{T: \"real\", Precision: 24}, Raw: \"real\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"0.0:::FLOAT8\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tNumeric\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 0}, Raw: \"numeric\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"0:::DECIMAL\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tDecimal\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 0}, Raw: \"numeric\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"0:::DECIMAL\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSmallSerial\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\", Unsigned: false}, Raw: \"bigint\", Null: false},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"unique_rowid()\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSerial\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\", Unsigned: false}, Raw: \"bigint\", Null: false},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"unique_rowid()\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tBigSerial\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\", Unsigned: false}, Raw: \"bigint\", Null: false},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"unique_rowid()\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSerial2\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\", Unsigned: false}, Raw: \"bigint\", Null: false},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"unique_rowid()\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSerial4\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\", Unsigned: false}, Raw: \"bigint\", Null: false},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"unique_rowid()\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSerial8\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\", Unsigned: false}, Raw: \"bigint\", Null: false},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"unique_rowid()\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tArray\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.ArrayType{Type: &schema.StringType{T: \"text\"}, T: \"text[]\"}, Raw: \"ARRAY\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"ARRAY[]:::STRING[]\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tJSON\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.JSONType{T: \"jsonb\"}, Raw: \"jsonb\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"'{\\\"key\\\": \\\"value\\\"}':::JSONB\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tJSONB\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.JSONType{T: \"jsonb\"}, Raw: \"jsonb\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"'{\\\"key\\\": \\\"value\\\"}':::JSONB\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tUUID\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.UUIDType{T: \"uuid\"}, Raw: \"uuid\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11':::UUID\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tInterval\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.IntervalType{T: \"interval\", Precision: intp(6)}, Raw: \"interval\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"'04:00:00':::INTERVAL\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tfor i, c := range expected.Columns {\n\t\t\trequire.EqualValues(t, ts.Columns[i], c, c.Name)\n\t\t}\n\t})\n\n\tt.Run(\"ImplicitIndexes\", func(t *testing.T) {\n\t\tcrdbRun(t, func(t *crdbTest) {\n\t\t\ttestImplicitIndexes(t, t.db)\n\t\t})\n\t})\n}\n\nfunc (t *crdbTest) url(_ string) string {\n\treturn fmt.Sprintf(\"postgres://root:pass@localhost:%d/defaultdb?sslmode=disable\", t.port)\n}\n\nfunc (t *crdbTest) driver() migrate.Driver {\n\treturn t.drv\n}\n\nfunc (t *crdbTest) revisionsStorage() migrate.RevisionReadWriter {\n\treturn t.rrw\n}\n\nfunc (t *crdbTest) applyHcl(spec string) {\n\trealm := t.loadRealm()\n\tvar desired schema.Schema\n\terr := postgres.EvalHCLBytes([]byte(spec), &desired, nil)\n\trequire.NoError(t, err)\n\texisting := realm.Schemas[0]\n\tdiff, err := t.drv.SchemaDiff(existing, &desired)\n\trequire.NoError(t, err)\n\terr = t.drv.ApplyChanges(context.Background(), diff)\n\trequire.NoError(t, err)\n}\n\nfunc (t *crdbTest) valueByVersion(values map[string]string, defaults string) string {\n\tif v, ok := values[t.version]; ok {\n\t\treturn v\n\t}\n\treturn defaults\n}\n\nfunc (t *crdbTest) loadRealm() *schema.Realm {\n\tr, err := t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\tSchemas: []string{\"public\"},\n\t\tMode:    schema.InspectSchemas | schema.InspectTables | schema.InspectTypes,\n\t})\n\trequire.NoError(t, err)\n\treturn r\n}\n\nfunc (t *crdbTest) loadUsers() *schema.Table {\n\treturn t.loadTable(\"users\")\n}\n\nfunc (t *crdbTest) loadPosts() *schema.Table {\n\treturn t.loadTable(\"posts\")\n}\n\nfunc (t *crdbTest) loadTable(name string) *schema.Table {\n\trealm := t.loadRealm()\n\trequire.Len(t, realm.Schemas, 1)\n\ttable, ok := realm.Schemas[0].Table(name)\n\trequire.True(t, ok)\n\treturn table\n}\n\nfunc (t *crdbTest) users() *schema.Table {\n\tusersT := &schema.Table{\n\t\tName:   \"users\",\n\t\tSchema: t.realm().Schemas[0],\n\t\tColumns: []*schema.Column{\n\t\t\t{\n\t\t\t\tName:  \"id\",\n\t\t\t\tType:  &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t\tAttrs: []schema.Attr{&postgres.Identity{}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"x\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t},\n\t\t},\n\t}\n\tusersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}\n\treturn usersT\n}\n\nfunc (t *crdbTest) posts() *schema.Table {\n\tusersT := t.users()\n\tpostsT := &schema.Table{\n\t\tName:   \"posts\",\n\t\tSchema: t.realm().Schemas[0],\n\t\tColumns: []*schema.Column{\n\t\t\t{\n\t\t\t\tName:  \"id\",\n\t\t\t\tType:  &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t\tAttrs: []schema.Attr{&postgres.Identity{}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"author_id\",\n\t\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"ctime\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"timestamp\", Type: &schema.TimeType{T: \"timestamp\"}},\n\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\tX: \"CURRENT_TIMESTAMP\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tAttrs: []schema.Attr{\n\t\t\t&schema.Comment{Text: \"posts comment\"},\n\t\t},\n\t}\n\tpostsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}\n\tpostsT.Indexes = []*schema.Index{\n\t\t{Name: \"author_id\", Parts: []*schema.IndexPart{{C: postsT.Columns[1]}}},\n\t\t{Name: \"id_author_id_unique\", Unique: true, Parts: []*schema.IndexPart{{C: postsT.Columns[1]}, {C: postsT.Columns[0]}}},\n\t}\n\tpostsT.ForeignKeys = []*schema.ForeignKey{\n\t\t{Symbol: \"author_id\", Table: postsT, Columns: postsT.Columns[1:2], RefTable: usersT, RefColumns: usersT.Columns[:1], OnDelete: schema.NoAction},\n\t}\n\treturn postsT\n}\n\nfunc (t *crdbTest) realm() *schema.Realm {\n\tr := &schema.Realm{\n\t\tSchemas: []*schema.Schema{\n\t\t\t{\n\t\t\t\tName: \"public\",\n\t\t\t},\n\t\t},\n\t}\n\tr.Schemas[0].Realm = r\n\treturn r\n}\n\nfunc (t *crdbTest) diff(t1, t2 *schema.Table) []schema.Change {\n\tchanges, err := t.drv.TableDiff(t1, t2)\n\trequire.NoError(t, err)\n\treturn changes\n}\n\nfunc (t *crdbTest) migrate(changes ...schema.Change) {\n\terr := t.drv.ApplyChanges(context.Background(), changes)\n\trequire.NoError(t, err)\n}\n\nfunc (t *crdbTest) dropTables(names ...string) {\n\tt.Cleanup(func() {\n\t\t_, err := t.db.Exec(\"DROP TABLE IF EXISTS \" + strings.Join(names, \", \"))\n\t\trequire.NoError(t.T, err, \"drop tables %q\", names)\n\t})\n}\n\nfunc (t *crdbTest) dropSchemas(names ...string) {\n\tt.Cleanup(func() {\n\t\t_, err := t.db.Exec(\"DROP SCHEMA IF EXISTS \" + strings.Join(names, \", \") + \" CASCADE\")\n\t\trequire.NoError(t.T, err, \"drop schema %q\", names)\n\t})\n}\nfunc (t *crdbTest) applyRealmHcl(spec string) {\n\trealm := t.loadRealm()\n\tvar desired schema.Realm\n\terr := postgres.EvalHCLBytes([]byte(spec), &desired, nil)\n\trequire.NoError(t, err)\n\tdiff, err := t.drv.RealmDiff(realm, &desired)\n\trequire.NoError(t, err)\n\terr = t.drv.ApplyChanges(context.Background(), diff)\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "internal/integration/docker-compose.yaml",
    "content": "services:\n  mysql56:\n    container_name: atlas-integration-mysql56\n    platform: linux/amd64\n    image: mysql:5.6.35\n    environment:\n      MYSQL_DATABASE: test\n      MYSQL_ROOT_PASSWORD: pass\n    healthcheck:\n      test: mysqladmin ping -ppass\n    ports:\n      - \"3306:3306\"\n\n  mysql57:\n    container_name: atlas-integration-mysql57\n    platform: linux/amd64\n    image: mysql:5.7.26\n    environment:\n      MYSQL_DATABASE: test\n      MYSQL_ROOT_PASSWORD: pass\n    healthcheck:\n      test: mysqladmin ping -ppass\n    ports:\n      - \"3307:3306\"\n\n  mysql8:\n    container_name: atlas-integration-mysql8\n    platform: linux/amd64\n    image: mysql:8.4\n    environment:\n      MYSQL_DATABASE: test\n      MYSQL_ROOT_PASSWORD: pass\n    healthcheck:\n      test: mysqladmin ping -ppass\n    ports:\n      - \"3308:3306\"\n\n  postgres-ext-postgis:\n    container_name: atlas-integration-postgres-ext-postgis\n    platform: linux/amd64\n    image: postgis/postgis:latest\n    environment:\n      POSTGRES_DB: test\n      POSTGRES_PASSWORD: pass\n    healthcheck:\n      test: pg_isready -U postgres\n    ports:\n      - \"5429:5432\"\n\n  postgres10:\n    container_name: atlas-integration-postgres10\n    platform: linux/amd64\n    image: postgres:10\n    environment:\n      POSTGRES_DB: test\n      POSTGRES_PASSWORD: pass\n    healthcheck:\n      test: pg_isready -U postgres\n    ports:\n      - \"5430:5432\"\n\n  postgres11:\n    container_name: atlas-integration-postgres11\n    platform: linux/amd64\n    image: postgres:11\n    environment:\n      POSTGRES_DB: test\n      POSTGRES_PASSWORD: pass\n    healthcheck:\n      test: pg_isready -U postgres\n    ports:\n      - \"5431:5432\"\n\n  postgres12:\n    container_name: atlas-integration-postgres12\n    platform: linux/amd64\n    image: postgres:12\n    environment:\n      POSTGRES_DB: test\n      POSTGRES_PASSWORD: pass\n    healthcheck:\n      test: pg_isready -U postgres\n    ports:\n      - \"5432:5432\"\n\n  postgres13:\n    container_name: atlas-integration-postgres13\n    platform: linux/amd64\n    image: postgres:13\n    environment:\n      POSTGRES_DB: test\n      POSTGRES_PASSWORD: pass\n    healthcheck:\n      test: pg_isready -U postgres\n    ports:\n      - \"5433:5432\"\n\n  postgres14:\n    container_name: atlas-integration-postgres14\n    platform: linux/amd64\n    image: postgres:14\n    environment:\n      POSTGRES_DB: test\n      POSTGRES_PASSWORD: pass\n    healthcheck:\n      test: pg_isready -U postgres\n    ports:\n      - \"5434:5432\"\n\n  postgres15:\n    container_name: atlas-integration-postgres15\n    platform: linux/amd64\n    image: postgres:15\n    environment:\n      POSTGRES_DB: test\n      POSTGRES_PASSWORD: pass\n    healthcheck:\n      test: pg_isready -U postgres\n    ports:\n      - \"5435:5432\"\n\n\n  mariadb:\n    container_name: atlas-integration-mariadb\n    platform: linux/amd64\n    image: mariadb\n    environment:\n      MYSQL_DATABASE: test\n      MYSQL_ROOT_PASSWORD: pass\n    healthcheck:\n      test: mysqladmin ping -ppass\n    ports:\n      - \"4306:3306\"\n\n  mariadb102:\n    container_name: atlas-integration-mariadb102\n    platform: linux/amd64\n    image: mariadb:10.2.32\n    environment:\n      MYSQL_DATABASE: test\n      MYSQL_ROOT_PASSWORD: pass\n    healthcheck:\n      test: mysqladmin ping -ppass\n    ports:\n      - \"4307:3306\"\n\n  mariadb103:\n    container_name: atlas-integration-mariadb103\n    platform: linux/amd64\n    image: mariadb:10.3.13\n    environment:\n      MYSQL_DATABASE: test\n      MYSQL_ROOT_PASSWORD: pass\n    healthcheck:\n      test: mysqladmin ping -ppass\n    ports:\n      - \"4308:3306\"\n\n  # Default DB test, No Password\n  tidb5:\n    container_name: atlas-integration-tidb5\n    platform: linux/amd64\n    image: pingcap/tidb:v5.4.0\n    ports:\n      - \"4309:4000\"\n\n  tidb6:\n    container_name: atlas-integration-tidb6\n    platform: linux/amd64\n    image: pingcap/tidb:v6.6.0\n    ports:\n      - \"4310:4000\"\n  \n  cockroach21.2.11:\n    container_name: atlas-integration-cockroach21.2.11\n    platform: linux/amd64\n    image: cockroachdb/cockroach:v21.2.11\n    ports:\n      - \"26257:26257\"\n    command: \"start-single-node --insecure\"\n"
  },
  {
    "path": "internal/integration/go.mod",
    "content": "module ariga.io/atlas/internal/integration\n\ngo 1.24.13\n\nreplace ariga.io/atlas => ../../\n\nreplace ariga.io/atlas/cmd/atlas => ../../cmd/atlas\n\nrequire (\n\tariga.io/atlas v0.32.1-0.20250325101103-175b25e1c1b9\n\tariga.io/atlas/cmd/atlas v0.13.2-0.20231220130200-d8bd6f612d7a\n\tgithub.com/go-sql-driver/mysql v1.9.3\n\tgithub.com/hashicorp/hcl/v2 v2.18.1\n\tgithub.com/lib/pq v1.10.9\n\tgithub.com/mattn/go-sqlite3 v1.14.28\n\tgithub.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e\n\tgithub.com/rogpeppe/go-internal v1.13.1\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/zclconf/go-cty v1.15.1\n)\n\nrequire (\n\tcloud.google.com/go/auth v0.16.3 // indirect\n\tcloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect\n\tcloud.google.com/go/compute/metadata v0.7.0 // indirect\n\tcloud.google.com/go/iam v1.5.2 // indirect\n\tcloud.google.com/go/longrunning v0.6.7 // indirect\n\tcloud.google.com/go/secretmanager v1.15.0 // indirect\n\tentgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4 // indirect\n\tfilippo.io/edwards25519 v1.1.0 // indirect\n\tgithub.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1 // indirect\n\tgithub.com/agext/levenshtein v1.2.3 // indirect\n\tgithub.com/antlr4-go/antlr/v4 v4.13.0 // indirect\n\tgithub.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect\n\tgithub.com/aws/aws-sdk-go v1.55.7 // indirect\n\tgithub.com/aws/aws-sdk-go-v2 v1.36.5 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/config v1.29.17 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect\n\tgithub.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect\n\tgithub.com/aws/smithy-go v1.22.4 // indirect\n\tgithub.com/bmatcuk/doublestar v1.3.4 // indirect\n\tgithub.com/chzyer/readline v1.5.1 // indirect\n\tgithub.com/coder/websocket v1.8.12 // indirect\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/fatih/color v1.16.0 // indirect\n\tgithub.com/felixge/httpsnoop v1.0.4 // indirect\n\tgithub.com/fsnotify/fsnotify v1.9.0 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-openapi/inflect v0.19.0 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/google/s2a-go v0.1.9 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/google/wire v0.6.0 // indirect\n\tgithub.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect\n\tgithub.com/googleapis/gax-go/v2 v2.15.0 // indirect\n\tgithub.com/hashicorp/go-cleanhttp v0.5.2 // indirect\n\tgithub.com/hashicorp/go-retryablehttp v0.7.7 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/jmespath/go-jmespath v0.4.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.13 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mitchellh/go-homedir v1.1.0 // indirect\n\tgithub.com/mitchellh/go-wordwrap v1.0.1 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/spf13/cobra v1.8.0 // indirect\n\tgithub.com/spf13/pflag v1.0.5 // indirect\n\tgithub.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d // indirect\n\tgithub.com/vektah/gqlparser/v2 v2.5.16 // indirect\n\tgithub.com/zclconf/go-cty-yaml v1.1.0 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.1.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect\n\tgo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect\n\tgo.opentelemetry.io/otel v1.37.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.37.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.37.0 // indirect\n\tgo.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.37.0 // indirect\n\tgocloud.dev v0.43.0 // indirect\n\tgolang.org/x/crypto v0.40.0 // indirect\n\tgolang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect\n\tgolang.org/x/mod v0.26.0 // indirect\n\tgolang.org/x/net v0.42.0 // indirect\n\tgolang.org/x/oauth2 v0.30.0 // indirect\n\tgolang.org/x/sync v0.16.0 // indirect\n\tgolang.org/x/sys v0.34.0 // indirect\n\tgolang.org/x/text v0.28.0 // indirect\n\tgolang.org/x/time v0.12.0 // indirect\n\tgolang.org/x/tools v0.35.0 // indirect\n\tgolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect\n\tgoogle.golang.org/api v0.242.0 // indirect\n\tgoogle.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 // indirect\n\tgoogle.golang.org/grpc v1.73.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.8 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "internal/integration/go.sum",
    "content": "cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs=\ncloud.google.com/go v0.121.4/go.mod h1:XEBchUiHFJbz4lKBZwYBDHV/rSyfFktk737TLDU089s=\ncloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc=\ncloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA=\ncloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=\ncloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=\ncloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=\ncloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=\ncloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=\ncloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=\ncloud.google.com/go/kms v1.22.0 h1:dBRIj7+GDeeEvatJeTB19oYZNV0aj6wEqSIT/7gLqtk=\ncloud.google.com/go/kms v1.22.0/go.mod h1:U7mf8Sva5jpOb4bxYZdtw/9zsbIjrklYwPcvMk34AL8=\ncloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=\ncloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=\ncloud.google.com/go/secretmanager v1.15.0 h1:RtkCMgTpaBMbzozcRUGfZe46jb9a3qh5EdEtVRUATF8=\ncloud.google.com/go/secretmanager v1.15.0/go.mod h1:1hQSAhKK7FldiYw//wbR/XPfPc08eQ81oBsnRUHEvUc=\nentgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4 h1:d7UZAvQCnOp1PyiHAWkPCXBEPW3tVjraiK/RZlsW0XY=\nentgo.io/ent v0.14.5-0.20250523082027-21ecfa0872d4/go.mod h1:zTzLmWtPvGpmSwtkaayM2cm5m819NdM7z7tYPq3vN0U=\nfilippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=\nfilippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=\ngithub.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1 h1:LejjvYg4tCW5HO7q/1nzPrprh47oUD9OUySQ29pDp5c=\ngithub.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1/go.mod h1:cnC/60IoLiDM0GhdKYJ6oO7AwpZe1IQfPnSKlAURgHw=\ngithub.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=\ngithub.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=\ngithub.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=\ngithub.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=\ngithub.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=\ngithub.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=\ngithub.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=\ngithub.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=\ngithub.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=\ngithub.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac=\ngithub.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=\ngithub.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=\ngithub.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0=\ngithub.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0=\ngithub.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU=\ngithub.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8=\ngithub.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16 h1:j+YO7Khxpk73ESxUpheUSw91qT42+LqNZiEjul1Dmnk=\ngithub.com/aws/aws-sdk-go-v2/feature/rds/auth v1.2.16/go.mod h1:laSv+AlZPuT/bpJQ2Xspq/oDKhB/XZLohISGTKU7DOg=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s=\ngithub.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM=\ngithub.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo=\ngithub.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=\ngithub.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI=\ngithub.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4=\ngithub.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7 h1:d+mnMa4JbJlooSbYQfrJpit/YINaB30JEVgrhtjZneA=\ngithub.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7/go.mod h1:1X1NotbcGHH7PCQJ98PsExSxsJj/VWzz8MfFz43+02M=\ngithub.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 h1:OwMzNDe5VVTXD4kGmeK/FtqAITiV8Mw4TCa8IyNO0as=\ngithub.com/aws/aws-sdk-go-v2/service/ssm v1.60.1/go.mod h1:IyVabkWrs8SNdOEZLyFFcW9bUltV4G6OQS0s6H20PHg=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=\ngithub.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg=\ngithub.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0=\ngithub.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w=\ngithub.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=\ngithub.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=\ngithub.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=\ngithub.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=\ngithub.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=\ngithub.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=\ngithub.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=\ngithub.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=\ngithub.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=\ngithub.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=\ngithub.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=\ngithub.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=\ngithub.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=\ngithub.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=\ngithub.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=\ngithub.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=\ngithub.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=\ngithub.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=\ngithub.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=\ngithub.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/go-replayers/grpcreplay v1.3.0 h1:1Keyy0m1sIpqstQmgz307zhiJ1pV4uIlFds5weTmxbo=\ngithub.com/google/go-replayers/grpcreplay v1.3.0/go.mod h1:v6NgKtkijC0d3e3RW8il6Sy5sqRVUwoQa4mHOGEy8DI=\ngithub.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk=\ngithub.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg=\ngithub.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=\ngithub.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=\ngithub.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=\ngithub.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=\ngithub.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=\ngithub.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=\ngithub.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=\ngithub.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=\ngithub.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=\ngithub.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=\ngithub.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=\ngithub.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=\ngithub.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=\ngithub.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=\ngithub.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=\ngithub.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=\ngithub.com/hashicorp/hcl/v2 v2.18.1 h1:6nxnOJFku1EuSawSD81fuviYUV8DxFr3fp2dUi3ZYSo=\ngithub.com/hashicorp/hcl/v2 v2.18.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=\ngithub.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=\ngithub.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=\ngithub.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=\ngithub.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=\ngithub.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=\ngithub.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=\ngithub.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=\ngithub.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=\ngithub.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=\ngithub.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=\ngithub.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=\ngithub.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=\ngithub.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=\ngithub.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=\ngithub.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU=\ngithub.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s=\ngithub.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8=\ngithub.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngithub.com/zclconf/go-cty v1.15.1 h1:RgQYm4j2EvoBRXOPxhUvxPzRrGDo1eCOhHXuGfrj5S0=\ngithub.com/zclconf/go-cty v1.15.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=\ngithub.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0=\ngithub.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=\ngo.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=\ngo.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 h1:rbRJ8BBoVMsQShESYZ0FkvcITu8X8QNwJogcLUmDNNw=\ngo.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU=\ngo.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY=\ngo.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=\ngo.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=\ngo.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=\ngo.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=\ngo.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=\ngo.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=\ngo.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=\ngo.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=\ngo.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=\ngo.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngocloud.dev v0.43.0 h1:aW3eq4RMyehbJ54PMsh4hsp7iX8cO/98ZRzJJOzN/5M=\ngocloud.dev v0.43.0/go.mod h1:eD8rkg7LhKUHrzkEdLTZ+Ty/vgPHPCd+yMQdfelQVu4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=\ngolang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=\ngolang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=\ngolang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=\ngolang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=\ngolang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=\ngolang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=\ngolang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=\ngolang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=\ngolang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=\ngolang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=\ngolang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=\ngolang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=\ngolang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=\ngolang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=\ngolang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=\ngolang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=\ngolang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=\ngolang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=\ngolang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=\ngolang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=\ngolang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=\ngolang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=\ngolang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=\ngolang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=\ngolang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=\ngolang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=\ngoogle.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg=\ngoogle.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=\ngoogle.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 h1:Nt6z9UHqSlIdIGJdz6KhTIs2VRx/iOsA5iE8bmQNcxs=\ngoogle.golang.org/genproto v0.0.0-20250715232539-7130f93afb79/go.mod h1:kTmlBHMPqR5uCZPBvwa2B18mvubkjyY3CRLI0c6fj0s=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 h1:iOye66xuaAK0WnkPuhQPUFy8eJcmwUXqGGP3om6IxX8=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79/go.mod h1:HKJDgKsFUnv5VAGeQjz8kxcgDP0HoE0iZNp0OdZNlhE=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 h1:1ZwqphdOdWYXsUHgMpU/101nCtf/kSp9hOrcvFsnl10=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=\ngoogle.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=\ngoogle.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=\ngoogle.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=\ngoogle.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "internal/integration/hclsqlspec/hclsqlspec_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage hclsqlspec\n\nimport (\n\t\"math/big\"\n\t\"testing\"\n\n\t\"github.com/zclconf/go-cty/cty\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/mysql\"\n\t\"ariga.io/atlas/sql/postgres\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlite\"\n\t\"ariga.io/atlas/sql/sqlspec\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nvar dialects = []struct {\n\tname string\n\tschemahcl.Marshaler\n\tEval func(b []byte, v any, inp map[string]cty.Value) error\n}{\n\t{\n\t\tname:      \"mysql\",\n\t\tMarshaler: mysql.MarshalHCL,\n\t\tEval:      mysql.EvalHCLBytes,\n\t},\n\t{\n\t\tname:      \"postgres\",\n\t\tMarshaler: postgres.MarshalHCL,\n\t\tEval:      postgres.EvalHCLBytes,\n\t},\n\t{\n\t\tname:      \"sqlite\",\n\t\tMarshaler: sqlite.MarshalHCL,\n\t\tEval:      sqlite.EvalHCLBytes,\n\t},\n}\n\nfunc TestHCL_SQL(t *testing.T) {\n\tfile, err := decode(`\nschema \"hi\" {\n\n}\n\ntable \"users\" {\n\tschema = schema.hi\n\t\n\tcolumn \"id\" {\n\t\ttype = int\n\t\tnull = false\n\t\tdefault = 123\n\t}\n\tcolumn \"age\" {\n\t\ttype = int\n\t\tnull = false\n\t\tdefault = 10\n\t}\n\tcolumn \"active\" {\n\t\ttype = boolean\n\t\tdefault = true\n\t}\n\n\tcolumn \"account_active\" {\n\t\ttype = boolean\n\t\tdefault \"DF_expr1\" {\n\t\t\tas = true\n\t\t}\n\t}\n\n\tprimary_key {\n\t\tcolumns = [table.users.column.id, table.users.column.age]\n\t}\n\t\n\tindex \"age\" {\n\t\tunique = true\n\t\tcolumns = [table.users.column.age]\n\t}\n\tindex \"active\" {\n\t\tunique = false\n\t\tcolumns = [table.users.column.active]\n\t}\n\n\tforeign_key \"fk\" {\n\t\tcolumns = [table.users.column.account_active]\n\t\tref_columns = [table.accounts.column.active]\n\t\ton_delete = \"SET NULL\"\n\t}\n}\n\ntable \"accounts\" {\n\tschema = schema.hi\n\t\n\tcolumn \"id\" {\n\t\ttype = int\n\t\tnull = false\n\t\tdefault = 123\n\t}\n\tcolumn \"age\" {\n\t\ttype = int\n\t\tnull = false\n\t\tdefault = 10\n\t}\n\tcolumn \"active\" {\n\t\ttype = boolean\n\t\tdefault = true\n\t}\n\n\tcolumn \"user_active\" {\n\t\ttype = boolean\n\t\tdefault = true\n\t}\n\n\tprimary_key {\n\t\tcolumns = [table.accounts.column.id]\n\t}\n\t\n\tindex \"age\" {\n\t\tunique = true\n\t\tcolumns = [table.accounts.column.age]\n\t}\n\tindex \"active\" {\n\t\tunique = false\n\t\tcolumns = [table.accounts.column.active]\n\t}\n\n\tforeign_key \"fk\" {\n\t\tcolumns = [table.accounts.column.user_active]\n\t\tref_columns = [table.users.column.active]\n\t\ton_delete = \"SET NULL\"\n\t}\n}\n\n`)\n\trequire.NoError(t, err)\n\texpected := &db{\n\t\tSchemas: []*sqlspec.Schema{\n\t\t\t{Name: \"hi\"},\n\t\t},\n\t\tTables: []*sqlspec.Table{\n\t\t\t{\n\t\t\t\tName:   \"users\",\n\t\t\t\tSchema: &schemahcl.Ref{V: \"$schema.hi\"},\n\t\t\t\tColumns: []*sqlspec.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"id\",\n\t\t\t\t\t\tType: &schemahcl.Type{T: \"int\"},\n\t\t\t\t\t\tNull: false,\n\t\t\t\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\t\t\t\t{K: \"default\", V: cty.NumberVal(big.NewFloat(123).SetPrec(512))},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"age\",\n\t\t\t\t\t\tType: &schemahcl.Type{T: \"int\"},\n\t\t\t\t\t\tNull: false,\n\t\t\t\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\t\t\t\t{K: \"default\", V: cty.NumberVal(big.NewFloat(10).SetPrec(512))},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"active\",\n\t\t\t\t\t\tType: &schemahcl.Type{T: \"boolean\"},\n\t\t\t\t\t\tNull: false,\n\t\t\t\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\t\t\t\t{K: \"default\", V: cty.BoolVal(true)},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"account_active\",\n\t\t\t\t\t\tType: &schemahcl.Type{T: \"boolean\"},\n\t\t\t\t\t\tNull: false,\n\t\t\t\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\t\t\t\tChildren: []*schemahcl.Resource{\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tType: \"default\",\n\t\t\t\t\t\t\t\t\t\tName: \"DF_expr1\",\n\t\t\t\t\t\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\t\t\t\t\t\t{K: \"as\", V: cty.BoolVal(true)},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tPrimaryKey: &sqlspec.PrimaryKey{\n\t\t\t\t\tColumns: []*schemahcl.Ref{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tV: \"$table.users.$column.id\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tV: \"$table.users.$column.age\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tIndexes: []*sqlspec.Index{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:   \"age\",\n\t\t\t\t\t\tUnique: true,\n\t\t\t\t\t\tColumns: []*schemahcl.Ref{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tV: \"$table.users.$column.age\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:   \"active\",\n\t\t\t\t\t\tUnique: false,\n\t\t\t\t\t\tColumns: []*schemahcl.Ref{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tV: \"$table.users.$column.active\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tForeignKeys: []*sqlspec.ForeignKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tSymbol: \"fk\",\n\t\t\t\t\t\tColumns: []*schemahcl.Ref{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tV: \"$table.users.$column.account_active\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tRefColumns: []*schemahcl.Ref{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tV: \"$table.accounts.$column.active\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tOnDelete: &schemahcl.Ref{V: string(schema.SetNull)},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:   \"accounts\",\n\t\t\t\tSchema: &schemahcl.Ref{V: \"$schema.hi\"},\n\t\t\t\tColumns: []*sqlspec.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"id\",\n\t\t\t\t\t\tType: &schemahcl.Type{T: \"int\"},\n\t\t\t\t\t\tNull: false,\n\t\t\t\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\t\t\t\t{K: \"default\", V: cty.NumberVal(big.NewFloat(123).SetPrec(512))},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"age\",\n\t\t\t\t\t\tType: &schemahcl.Type{T: \"int\"},\n\t\t\t\t\t\tNull: false,\n\t\t\t\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\t\t\t\t{K: \"default\", V: cty.NumberVal(big.NewFloat(10).SetPrec(512))},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"active\",\n\t\t\t\t\t\tType: &schemahcl.Type{T: \"boolean\"},\n\t\t\t\t\t\tNull: false,\n\t\t\t\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\t\t\t\t{K: \"default\", V: cty.BoolVal(true)},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"user_active\",\n\t\t\t\t\t\tType: &schemahcl.Type{T: \"boolean\"},\n\t\t\t\t\t\tNull: false,\n\t\t\t\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\t\t\t\t{K: \"default\", V: cty.BoolVal(true)},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tPrimaryKey: &sqlspec.PrimaryKey{\n\t\t\t\t\tColumns: []*schemahcl.Ref{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tV: \"$table.accounts.$column.id\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tIndexes: []*sqlspec.Index{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:   \"age\",\n\t\t\t\t\t\tUnique: true,\n\t\t\t\t\t\tColumns: []*schemahcl.Ref{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tV: \"$table.accounts.$column.age\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:   \"active\",\n\t\t\t\t\t\tUnique: false,\n\t\t\t\t\t\tColumns: []*schemahcl.Ref{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tV: \"$table.accounts.$column.active\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tForeignKeys: []*sqlspec.ForeignKey{\n\t\t\t\t\t{\n\t\t\t\t\t\tSymbol: \"fk\",\n\t\t\t\t\t\tColumns: []*schemahcl.Ref{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tV: \"$table.accounts.$column.user_active\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tRefColumns: []*schemahcl.Ref{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tV: \"$table.users.$column.active\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tOnDelete: &schemahcl.Ref{V: string(schema.SetNull)},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trequire.EqualValues(t, expected, file)\n}\n\nfunc TestWithRemain(t *testing.T) {\n\tfile, err := decode(`\nschema \"hi\" {\n\tx = 1\n}`)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, &db{\n\t\tSchemas: []*sqlspec.Schema{\n\t\t\t{\n\t\t\t\tName: \"hi\",\n\t\t\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\t\t\tExtra: schemahcl.Resource{\n\t\t\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\t\t\tschemahcl.IntAttr(\"x\", 1),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, file)\n}\n\nfunc TestMultiTable(t *testing.T) {\n\t_, err := decode(`\nschema \"hi\" {\n\n}\n\ntable \"users\" {\n\tschema = schema.hi\n\tcolumn \"id\" {\n\t\ttype = int\n\t\tunsigned = true\n\t\tnull = false\n\t\tdefault = 123\n\t}\n}\n\ntable \"accounts\" {\n\tschema = schema.hi\n\tcolumn \"id\" {\n\t\ttype = varchar(255)\n\t}\n\tindex \"name\" {\n\t\tunique = true\n\t}\n}\n\n`)\n\trequire.NoError(t, err)\n}\n\nvar hcl = schemahcl.New(schemahcl.WithTypes(\"table.column.type\", postgres.TypeRegistry.Specs()))\n\nfunc TestMarshalTopLevel(t *testing.T) {\n\tc := &sqlspec.Schema{\n\t\tName: \"schema\",\n\t}\n\th, err := hcl.MarshalSpec(c)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, `schema \"schema\" {\n}\n`, string(h))\n}\n\nfunc TestRealm(t *testing.T) {\n\tf := `schema \"account_a\" {\n}\ntable \"t1\" {\n\tschema = schema.account_a\n}\nschema \"account_b\" {\n}\ntable \"t2\" {\n\tschema = schema.account_b\n}\n`\n\n\tfor _, tt := range dialects {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tvar r schema.Realm\n\t\t\terr := tt.Eval([]byte(f), &r, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\texp := &schema.Realm{\n\t\t\t\tSchemas: []*schema.Schema{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"account_a\",\n\t\t\t\t\t\tRealm: &r,\n\t\t\t\t\t\tTables: []*schema.Table{\n\t\t\t\t\t\t\t{Name: \"t1\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"account_b\",\n\t\t\t\t\t\tRealm: &r,\n\t\t\t\t\t\tTables: []*schema.Table{\n\t\t\t\t\t\t\t{Name: \"t2\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\texp.Schemas[0].Tables[0].Schema = exp.Schemas[0]\n\t\t\texp.Schemas[1].Tables[0].Schema = exp.Schemas[1]\n\t\t\trequire.EqualValues(t, exp, &r)\n\t\t\thcl, err := tt.MarshalSpec(&r)\n\t\t\trequire.NoError(t, err)\n\t\t\tvar after schema.Realm\n\t\t\terr = tt.Eval(hcl, &after, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.EqualValues(t, exp, &after)\n\t\t})\n\t}\n}\n\nfunc TestUnsignedImmutability(t *testing.T) {\n\tf := `table \"users\" {\n\tschema = schema.test\n\tcolumn \"id\" {\n\t\ttype = bigint\n\t\tunsigned = true\n\t}\n\tcolumn \"shouldnt\" {\n\t\ttype = bigint\n\t}\n}\nschema \"test\" {\n}`\n\tvar s schema.Schema\n\terr := mysql.EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\ttbl := s.Tables[0]\n\trequire.EqualValues(t, &schema.IntegerType{T: \"bigint\", Unsigned: true}, tbl.Columns[0].Type.Type)\n\trequire.EqualValues(t, &schema.IntegerType{T: \"bigint\", Unsigned: false}, tbl.Columns[1].Type.Type)\n}\n\nfunc TestTablesWithQualifiers(t *testing.T) {\n\th := `\nschema \"a\" {}\nschema \"b\" {}\n\ntable \"a\" \"users\" {\n\tschema = schema.a\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tcolumn \"friend_id\" {\n\t\ttype = int\n\t}\n\tforeign_key \"friend_b\" {\n\t\tcolumns = [column.friend_id]\n\t\tref_columns = [table.b.users.column.id]\n\t}\n}\n\ntable \"b\" \"users\" {\n\tschema = schema.b\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tcolumn \"friend_id\" {\n\t\ttype = int\n\t}\n\tforeign_key \"friend_a\" {\n\t\tcolumns = [column.friend_id]\n\t\tref_columns = [table.a.users.column.id]\n\t}\n}\n`\n\tvar r schema.Realm\n\terr := mysql.EvalHCLBytes([]byte(h), &r, nil)\n\trequire.NoError(t, err)\n\n\trequire.EqualValues(t, r.Schemas[0].Tables[0].Columns[0], r.Schemas[1].Tables[0].ForeignKeys[0].RefColumns[0])\n\trequire.EqualValues(t, \"b\", r.Schemas[0].Tables[0].ForeignKeys[0].RefTable.Schema.Name)\n}\n\nfunc TestQualifyMarshal(t *testing.T) {\n\tfor _, tt := range dialects {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tr := schema.NewRealm(\n\t\t\t\tschema.New(\"a\").\n\t\t\t\t\tAddTables(\n\t\t\t\t\t\tschema.NewTable(\"users\"),\n\t\t\t\t\t\tschema.NewTable(\"tbl_a\"),\n\t\t\t\t\t),\n\t\t\t\tschema.New(\"b\").\n\t\t\t\t\tAddTables(\n\t\t\t\t\t\tschema.NewTable(\"users\"),\n\t\t\t\t\t\tschema.NewTable(\"tbl_b\"),\n\t\t\t\t\t),\n\t\t\t\tschema.New(\"c\").\n\t\t\t\t\tAddTables(\n\t\t\t\t\t\tschema.NewTable(\"users\"),\n\t\t\t\t\t\tschema.NewTable(\"tbl_c\"),\n\t\t\t\t\t),\n\t\t\t)\n\t\t\th, err := tt.Marshaler.MarshalSpec(r)\n\t\t\trequire.NoError(t, err)\n\t\t\texpected := `table \"a\" \"users\" {\n  schema = schema.a\n}\ntable \"tbl_a\" {\n  schema = schema.a\n}\ntable \"b\" \"users\" {\n  schema = schema.b\n}\ntable \"tbl_b\" {\n  schema = schema.b\n}\ntable \"c\" \"users\" {\n  schema = schema.c\n}\ntable \"tbl_c\" {\n  schema = schema.c\n}\nschema \"a\" {\n}\nschema \"b\" {\n}\nschema \"c\" {\n}\n`\n\t\t\trequire.EqualValues(t, expected, string(h))\n\t\t})\n\t}\n\n}\n\nfunc decode(f string) (*db, error) {\n\td := &db{}\n\tif err := hcl.EvalBytes([]byte(f), d, nil); err != nil {\n\t\treturn nil, err\n\t}\n\treturn d, nil\n}\n\ntype db struct {\n\tSchemas []*sqlspec.Schema `spec:\"schema\"`\n\tTables  []*sqlspec.Table  `spec:\"table\"`\n}\n"
  },
  {
    "path": "internal/integration/integration_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage integration\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"text/template\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nvar (\n\tdbs         []io.Closer\n\tflagVersion string\n)\n\nfunc TestMain(m *testing.M) {\n\tflag.StringVar(&flagVersion, \"version\", \"\", \"[mysql56, postgres10, tidb5, ...] what version to test\")\n\tflag.Parse()\n\tcode := m.Run()\n\tfor _, db := range dbs {\n\t\tdb.Close()\n\t}\n\tos.Exit(code)\n}\n\nfunc TestCLI_Interrupt(t *testing.T) {\n\tvar (\n\t\tstdout, stderr bytes.Buffer\n\t\tconnected      = make(chan struct{})\n\t\tsignal         = make(chan struct{})\n\t\thandler        = func(c net.Conn) {\n\t\t\tconnected <- struct{}{}\n\t\t\t<-signal // wait for signal sent\n\t\t\tc.Close()\n\t\t}\n\t)\n\tt.Cleanup(func() {\n\t\tclose(connected)\n\t\tclose(signal)\n\t})\n\n\t// First interrupt will not cancel the process, only print a warning.\n\tvar (\n\t\tport = newListener(t, handler)\n\t\tcmd  = exec.Command(\n\t\t\texecPath(t),\n\t\t\t\"schema\", \"inspect\",\n\t\t\t\"--url\", fmt.Sprintf(\"postgres://user:pass@localhost:%d/db?sslmode=disable\", port), // mock not responding db\n\t\t)\n\t)\n\tcmd.Stdout = &stdout\n\tcmd.Stderr = &stderr\n\trequire.NoError(t, cmd.Start())\n\t<-connected // wait for connection\n\trequire.NoError(t, cmd.Process.Signal(os.Interrupt))\n\tsignal <- struct{}{}\n\trequire.Error(t, cmd.Wait())\n\trequire.Equal(t, \"\\ninterrupt received, wait for exit or ^C to terminate\\n\", stdout.String())\n\trequire.Contains(t, stderr.String(), \"read: connection reset by peer\") // server closed\n\n\t// Two interrupts force stop\n\tr, w := io.Pipe()\n\tport = newListener(t, handler)\n\tcmd = exec.Command(\n\t\texecPath(t),\n\t\t\"schema\", \"inspect\",\n\t\t\"--url\", fmt.Sprintf(\"postgres://user:pass@localhost:%d/db?sslmode=disable\", port), // mock not responding db\n\t)\n\tcmd.Stdout = w\n\trequire.NoError(t, cmd.Start())\n\t<-connected // wait for connection\n\trequire.NoError(t, cmd.Process.Signal(os.Interrupt))\n\t// Wait for the cmd to print the warning (it works, we checked before) and then issue the second signal.\n\tbr := bufio.NewReader(r)\n\t_, err := br.ReadString('\\n')\n\trequire.NoError(t, err)\n\tout, err := br.ReadString('\\n')\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"interrupt received, wait for exit or ^C to terminate\\n\", out)\n\trequire.NoError(t, cmd.Process.Signal(os.Interrupt))\n\trequire.Error(t, cmd.Wait())\n}\n\nfunc newListener(t *testing.T, handler func(c net.Conn)) int {\n\ta, err := net.ResolveTCPAddr(\"tcp\", \"localhost:0\")\n\trequire.NoError(t, err)\n\tl, err := net.ListenTCP(\"tcp\", a)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() { l.Close() })\n\tgo func() {\n\t\tc, err := l.Accept()\n\t\trequire.NoError(t, err)\n\t\thandler(c)\n\t}()\n\treturn l.Addr().(*net.TCPAddr).Port\n}\n\n// T holds the elements common between dialect tests.\ntype T interface {\n\ttesting.TB\n\turl(string) string\n\tdriver() migrate.Driver\n\trevisionsStorage() migrate.RevisionReadWriter\n\trealm() *schema.Realm\n\tloadRealm() *schema.Realm\n\tusers() *schema.Table\n\tloadUsers() *schema.Table\n\tposts() *schema.Table\n\tloadPosts() *schema.Table\n\tloadTable(string) *schema.Table\n\tdropTables(...string)\n\tdropSchemas(...string)\n\tmigrate(...schema.Change)\n\tdiff(*schema.Table, *schema.Table) []schema.Change\n\tapplyHcl(spec string)\n\tapplyRealmHcl(spec string)\n}\n\nfunc testAddDrop(t T) {\n\tusersT := t.users()\n\tpostsT := t.posts()\n\tpetsT := &schema.Table{\n\t\tName:   \"pets\",\n\t\tSchema: usersT.Schema,\n\t\tColumns: []*schema.Column{\n\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t{Name: \"owner_id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}, Null: true}},\n\t\t},\n\t}\n\tpetsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}\n\tpetsT.ForeignKeys = []*schema.ForeignKey{\n\t\t{Symbol: \"owner_id\", Table: petsT, Columns: petsT.Columns[1:], RefTable: usersT, RefColumns: usersT.Columns[:1]},\n\t}\n\tif tt, ok := t.(interface {\n\t\tpets(_, _ *schema.Table) *schema.Table\n\t}); ok {\n\t\tpetsT = tt.pets(usersT, postsT)\n\t}\n\tt.dropTables(postsT.Name, usersT.Name, petsT.Name)\n\tt.migrate(&schema.AddTable{T: petsT}, &schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})\n\tensureNoChange(t, usersT, petsT, postsT)\n\tt.migrate(&schema.DropTable{T: usersT}, &schema.DropTable{T: postsT}, &schema.DropTable{T: petsT})\n\t// Ensure the realm has no tables.\n\tfor _, s := range t.loadRealm().Schemas {\n\t\trequire.Empty(t, s.Tables)\n\t}\n}\n\nfunc testRelation(t T) {\n\tusersT, postsT := t.users(), t.posts()\n\tt.dropTables(postsT.Name, usersT.Name)\n\tt.migrate(\n\t\t&schema.AddTable{T: usersT},\n\t\t&schema.AddTable{T: postsT},\n\t)\n\tensureNoChange(t, postsT, usersT)\n}\n\nfunc testImplicitIndexes(t T, db *sql.DB) {\n\tconst (\n\t\tname = \"implicit_indexes\"\n\t\tddl  = \"create table implicit_indexes(c1 int unique, c2 int unique, unique(c1,c2), unique(c2,c1))\"\n\t)\n\tt.dropTables(name)\n\t_, err := db.Exec(ddl)\n\trequire.NoError(t, err)\n\tcurrent := t.loadTable(name)\n\tc1, c2 := schema.NewNullIntColumn(\"c1\", \"int\"), schema.NewNullIntColumn(\"c2\", \"int\")\n\tdesired := schema.NewTable(name).\n\t\tAddColumns(c1, c2).\n\t\tAddIndexes(\n\t\t\tschema.NewUniqueIndex(\"\").AddColumns(c1),\n\t\t\tschema.NewUniqueIndex(\"\").AddColumns(c2),\n\t\t\tschema.NewUniqueIndex(\"\").AddColumns(c1, c2),\n\t\t\tschema.NewUniqueIndex(\"\").AddColumns(c2, c1),\n\t\t)\n\tchanges := t.diff(current, desired)\n\trequire.Empty(t, changes)\n\tdesired.AddIndexes(\n\t\tschema.NewIndex(\"c1_key\").AddColumns(c1),\n\t\tschema.NewIndex(\"c2_key\").AddColumns(c2),\n\t)\n\tchanges = t.diff(current, desired)\n\trequire.NotEmpty(t, changes)\n\tt.migrate(&schema.ModifyTable{T: desired, Changes: changes})\n\tensureNoChange(t, desired)\n}\n\nfunc testHCLIntegration(t T, full string, empty string) {\n\tt.applyHcl(full)\n\tusers := t.loadUsers()\n\tposts := t.loadPosts()\n\tt.dropTables(users.Name, posts.Name)\n\tcolumn, ok := users.Column(\"id\")\n\trequire.True(t, ok, \"expected id column\")\n\trequire.Equal(t, \"users\", users.Name)\n\tcolumn, ok = posts.Column(\"author_id\")\n\trequire.Equal(t, \"author_id\", column.Name)\n\tt.applyHcl(empty)\n\trequire.Empty(t, t.realm().Schemas[0].Tables)\n}\n\nfunc testCLIMigrateApplyBC(t T, dialect string) {\n\tctx := context.Background()\n\n\tt.dropSchemas(\"bc_test\", \"bc_test_2\", \"atlas_schema_revisions\")\n\tt.dropTables(\"bc_tbl\", \"atlas_schema_revisions\")\n\tt.migrate(&schema.AddSchema{S: schema.New(\"bc_test\")})\n\n\t// Connection to schema with flag will respect flag (also mimics \"old\" behavior).\n\tout, err := exec.Command(\n\t\texecPath(t),\n\t\t\"migrate\", \"apply\",\n\t\t\"--allow-dirty\", // since database does contain more than one schema\n\t\t\"--dir\", \"file://testdata/migrations/\"+dialect,\n\t\t\"--url\", t.url(\"bc_test\"),\n\t\t\"--revisions-schema\", \"atlas_schema_revisions\",\n\t).CombinedOutput()\n\trequire.NoError(t, err, string(out))\n\ts, err := t.driver().InspectSchema(ctx, \"atlas_schema_revisions\", &schema.InspectOptions{\n\t\tMode: schema.InspectSchemas | schema.InspectTables,\n\t})\n\trequire.NoError(t, err)\n\t_, ok := s.Table(\"atlas_schema_revisions\")\n\trequire.True(t, ok)\n\n\t// Connection to realm will see the existing schema and will not attempt to migrate.\n\tout, err = exec.Command(\n\t\texecPath(t),\n\t\t\"migrate\", \"apply\",\n\t\t\"--dir\", \"file://testdata/migrations/\"+dialect,\n\t\t\"--url\", t.url(\"\"),\n\t).CombinedOutput()\n\trequire.NoError(t, err, string(out))\n\trequire.Equal(t, \"No migration files to execute\\n\", string(out))\n\n\t// Connection to schema without flag will error.\n\tout, err = exec.Command(\n\t\texecPath(t),\n\t\t\"migrate\", \"apply\",\n\t\t\"--dir\", \"file://testdata/migrations/\"+dialect,\n\t\t\"--url\", t.url(\"bc_test\"),\n\t).CombinedOutput()\n\trequire.Error(t, err)\n\trequire.Contains(t, string(out), \"We couldn't find a revision table in the connected schema but found one in\")\n\n\t// Providing the flag and we are good.\n\tout, err = exec.Command(\n\t\texecPath(t),\n\t\t\"migrate\", \"apply\",\n\t\t\"--dir\", \"file://testdata/migrations/\"+dialect,\n\t\t\"--url\", t.url(\"bc_test\"),\n\t\t\"--revisions-schema\", \"atlas_schema_revisions\",\n\t).CombinedOutput()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"No migration files to execute\\n\", string(out))\n\n\t// Providing the flag to the schema instead will work as well.\n\tt.migrate(\n\t\t&schema.DropSchema{S: schema.New(\"bc_test\")},\n\t\t&schema.AddSchema{S: schema.New(\"bc_test\")},\n\t)\n\tout, err = exec.Command(\n\t\texecPath(t),\n\t\t\"migrate\", \"apply\",\n\t\t\"--dir\", \"file://testdata/migrations/\"+dialect,\n\t\t\"--url\", t.url(\"bc_test\"),\n\t\t\"--revisions-schema\", \"bc_test\",\n\t).CombinedOutput()\n\trequire.NoError(t, err, string(out))\n\trequire.NotContains(t, string(out), \"No migration files to execute\\n\")\n\n\t// Consecutive attempts do not need the flag anymore.\n\tout, err = exec.Command(\n\t\texecPath(t),\n\t\t\"migrate\", \"apply\",\n\t\t\"--dir\", \"file://testdata/migrations/\"+dialect,\n\t\t\"--url\", t.url(\"bc_test\"),\n\t).CombinedOutput()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"No migration files to execute\\n\", string(out))\n\n\t// Last, if bound to schema and no \"old\" behavior extra schema does\n\t// exist, the revision table will be saved in the connected one.\n\tt.migrate(\n\t\t&schema.DropSchema{S: schema.New(\"atlas_schema_revisions\")},\n\t\t&schema.DropSchema{S: schema.New(\"bc_test\")},\n\t\t&schema.AddSchema{S: schema.New(\"bc_test_2\")},\n\t)\n\tout, err = exec.Command(\n\t\texecPath(t),\n\t\t\"migrate\", \"apply\",\n\t\t\"--allow-dirty\", // since database does contain more than one schema\n\t\t\"--dir\", \"file://testdata/migrations/\"+dialect,\n\t\t\"--url\", t.url(\"bc_test_2\"),\n\t).CombinedOutput()\n\trequire.NoError(t, err, string(out))\n\ts, err = t.driver().InspectSchema(ctx, \"atlas_schema_revisions\", &schema.InspectOptions{\n\t\tMode: schema.InspectSchemas | schema.InspectTables,\n\t})\n\trequire.True(t, schema.IsNotExistError(err))\n\ts, err = t.driver().InspectSchema(ctx, \"bc_test_2\", &schema.InspectOptions{\n\t\tMode: schema.InspectSchemas | schema.InspectTables,\n\t})\n\trequire.NoError(t, err)\n\t_, ok = s.Table(\"atlas_schema_revisions\")\n\trequire.True(t, ok)\n}\n\nfunc testCLISchemaInspect(t T, h string, url string, eval schemahcl.Evaluator, args ...string) {\n\tt.dropTables(\"users\")\n\tvar expected schema.Schema\n\terr := evalBytes([]byte(h), &expected, eval)\n\trequire.NoError(t, err)\n\tt.applyHcl(h)\n\trunArgs := []string{\n\t\t\"schema\",\n\t\t\"inspect\",\n\t\t\"-u\",\n\t\turl,\n\t}\n\trunArgs = append(runArgs, args...)\n\tcmd := exec.Command(execPath(t), runArgs...)\n\tstdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)\n\tcmd.Stderr = stderr\n\tcmd.Stdout = stdout\n\trequire.NoError(t, cmd.Run(), stderr.String())\n\tvar actual schema.Schema\n\terr = evalBytes(stdout.Bytes(), &actual, eval)\n\trequire.NoError(t, err)\n\trequire.Empty(t, stderr.String())\n\trequire.Equal(t, expected, actual)\n}\n\nfunc testCLISchemaInspectEnv(t T, h string, env string, eval schemahcl.Evaluator) {\n\tt.dropTables(\"users\")\n\tvar expected schema.Schema\n\terr := evalBytes([]byte(h), &expected, eval)\n\trequire.NoError(t, err)\n\tt.applyHcl(h)\n\tcmd := exec.Command(execPath(t),\n\t\t\"schema\",\n\t\t\"inspect\",\n\t\t\"--env\",\n\t\tenv,\n\t)\n\tstdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)\n\tcmd.Stderr = stderr\n\tcmd.Stdout = stdout\n\trequire.NoError(t, cmd.Run(), stderr.String())\n\tvar actual schema.Schema\n\terr = evalBytes(stdout.Bytes(), &actual, eval)\n\trequire.NoError(t, err)\n\trequire.Empty(t, stderr.String())\n\trequire.Equal(t, expected, actual)\n}\n\n// initOnce controls that the cli will only be built once.\nvar initOnce sync.Once\n\nfunc execPath(t testing.TB) string {\n\tinitOnce.Do(func() {\n\t\targs := []string{\n\t\t\t\"build\",\n\t\t\t\"-mod=mod\",\n\t\t\t\"-o\", filepath.Join(os.TempDir(), \"atlas\"),\n\t\t}\n\t\targs = append(args, buildFlags...)\n\t\targs = append(args, \"ariga.io/atlas/cmd/atlas\")\n\t\tout, err := exec.Command(\"go\", args...).CombinedOutput()\n\t\trequire.NoError(t, err, string(out))\n\t})\n\treturn filepath.Join(os.TempDir(), \"atlas\")\n}\n\nfunc testCLIMultiSchemaApply(t T, h string, url string, schemas []string, eval schemahcl.Evaluator) {\n\tf := filepath.Join(t.TempDir(), \"schema.hcl\")\n\terr := os.WriteFile(f, []byte(h), 0644)\n\trequire.NoError(t, err)\n\trequire.NoError(t, err)\n\tvar expected schema.Realm\n\terr = evalBytes([]byte(h), &expected, eval)\n\trequire.NoError(t, err)\n\tcmd := exec.Command(execPath(t),\n\t\t\"schema\",\n\t\t\"apply\",\n\t\t\"-f\",\n\t\tf,\n\t\t\"-u\",\n\t\turl,\n\t\t\"-s\",\n\t\tstrings.Join(schemas, \",\"),\n\t)\n\tstdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)\n\tcmd.Stderr = stderr\n\tcmd.Stdout = stdout\n\tstdin, err := cmd.StdinPipe()\n\trequire.NoError(t, err)\n\tdefer stdin.Close()\n\t_, err = io.WriteString(stdin, \"\\n\")\n\trequire.NoError(t, cmd.Run(), stderr.String())\n\trequire.True(t, strings.Contains(stdout.String(), `CREATE SCHEMA`) || strings.Contains(stdout.String(), `CREATE DATABASE`), \"create schema test2\")\n}\n\nfunc testCLIMultiSchemaInspect(t T, h string, url string, schemas []string, eval schemahcl.Evaluator) {\n\tvar expected schema.Realm\n\terr := evalBytes([]byte(h), &expected, eval)\n\trequire.NoError(t, err)\n\tt.applyRealmHcl(h)\n\tcmd := exec.Command(execPath(t),\n\t\t\"schema\",\n\t\t\"inspect\",\n\t\t\"-u\",\n\t\turl,\n\t\t\"-s\",\n\t\tstrings.Join(schemas, \",\"),\n\t)\n\tstdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)\n\tcmd.Stderr = stderr\n\tcmd.Stdout = stdout\n\trequire.NoError(t, cmd.Run(), stderr.String())\n\tvar actual schema.Realm\n\terr = evalBytes(stdout.Bytes(), &actual, eval)\n\trequire.NoError(t, err)\n\trequire.Empty(t, stderr.String())\n\trequire.Equal(t, expected, actual)\n}\n\nfunc testCLISchemaApply(t T, h string, url string, args ...string) {\n\tt.dropTables(\"users\")\n\tf := filepath.Join(t.TempDir(), \"schema.hcl\")\n\terr := os.WriteFile(f, []byte(h), 0644)\n\trequire.NoError(t, err)\n\trunArgs := append([]string{\n\t\t\"schema\", \"apply\",\n\t\t\"-u\", url,\n\t\t\"-f\", f,\n\t}, args...)\n\t// Append the --dev-url only if it is not already present.\n\tif !slices.Contains(args, \"--dev-url\") {\n\t\targs = append(args, \"--dev-url\", url)\n\t}\n\tcmd := exec.Command(execPath(t), runArgs...)\n\tstdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)\n\tcmd.Stderr = stderr\n\tcmd.Stdout = stdout\n\tstdin, err := cmd.StdinPipe()\n\trequire.NoError(t, err)\n\tdefer stdin.Close()\n\t_, err = io.WriteString(stdin, \"\\n\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmd.Run(), stderr.String(), stdout.String())\n\trequire.Empty(t, stderr.String(), stderr.String())\n\trequire.Contains(t, stdout.String(), \"CREATE TABLE\")\n\tu := t.loadUsers()\n\trequire.NotNil(t, u)\n}\n\nfunc testCLISchemaApplyDry(t T, h string, url string) {\n\tt.dropTables(\"users\")\n\tf := filepath.Join(t.TempDir(), \"schema.hcl\")\n\terr := os.WriteFile(f, []byte(h), 0644)\n\trequire.NoError(t, err)\n\tcmd := exec.Command(execPath(t),\n\t\t\"schema\",\n\t\t\"apply\",\n\t\t\"-u\",\n\t\turl,\n\t\t\"-f\",\n\t\tf,\n\t\t\"--dry-run\",\n\t)\n\tstdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)\n\tcmd.Stderr = stderr\n\tcmd.Stdout = stdout\n\tstdin, err := cmd.StdinPipe()\n\trequire.NoError(t, err)\n\tdefer stdin.Close()\n\t_, err = io.WriteString(stdin, \"\\n\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmd.Run(), stderr.String(), stdout.String())\n\trequire.Empty(t, stderr.String(), stderr.String())\n\trequire.Contains(t, stdout.String(), \"CREATE TABLE\")\n\trequire.NotContains(t, stdout.String(), \"Are you sure?\", \"dry run should not prompt\")\n\trealm := t.loadRealm()\n\t_, ok := realm.Schemas[0].Table(\"users\")\n\trequire.False(t, ok, \"expected users table not to be created\")\n}\n\nfunc testCLISchemaApplyAutoApprove(t T, h string, url string, args ...string) {\n\tt.dropTables(\"users\")\n\tf := filepath.Join(t.TempDir(), \"schema.hcl\")\n\terr := os.WriteFile(f, []byte(h), 0644)\n\trequire.NoError(t, err)\n\trunArgs := []string{\n\t\t\"schema\",\n\t\t\"apply\",\n\t\t\"-u\",\n\t\turl,\n\t\t\"-f\",\n\t\tf,\n\t\t\"--auto-approve\",\n\t}\n\trunArgs = append(runArgs, args...)\n\tcmd := exec.Command(execPath(t), runArgs...)\n\tstdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)\n\tcmd.Stderr = stderr\n\tcmd.Stdout = stdout\n\trequire.NoError(t, err)\n\trequire.NoError(t, cmd.Run(), stderr.String(), stdout.String())\n\trequire.Empty(t, stderr.String(), stderr.String())\n\trequire.Contains(t, stdout.String(), \"CREATE TABLE\")\n\tu := t.loadUsers()\n\trequire.NotNil(t, u)\n}\n\nfunc testCLISchemaApplyFromMigrationDir(t T) {\n\tconst (\n\t\tdbname  = \"apply_migration_dir\"\n\t\tdevname = dbname + \"_dev\"\n\t)\n\tt.dropSchemas(dbname, devname)\n\tt.migrate(&schema.AddSchema{S: schema.New(dbname)}, &schema.AddSchema{S: schema.New(devname)})\n\tdefer t.migrate(&schema.DropSchema{S: schema.New(dbname)}, &schema.DropSchema{S: schema.New(devname)})\n\n\tusers, err := t.driver().SchemaDiff(schema.New(\"\"), schema.New(\"\").AddTables(t.users()))\n\trequire.NoError(t, err)\n\tusersT := t.users()\n\tusersT.Name = \"users_2\"\n\tusers2, err := t.driver().SchemaDiff(schema.New(\"\"), schema.New(\"\").AddTables(usersT))\n\trequire.NoError(t, err)\n\n\topts := []migrate.PlanOption{\n\t\tfunc(o *migrate.PlanOptions) { o.Indent, o.SchemaQualifier = \"  \", new(string) },\n\t}\n\taddUsers, err := t.driver().PlanChanges(context.Background(), \"\", users, opts...)\n\trequire.NoError(t, err)\n\taddUsers2, err := t.driver().PlanChanges(context.Background(), \"\", users2, opts...)\n\trequire.NoError(t, err)\n\n\tvar (\n\t\tfn = func(c []*migrate.Change) string {\n\t\t\tvar buf strings.Builder\n\t\t\tfor _, c := range c {\n\t\t\t\tbuf.WriteString(c.Cmd)\n\t\t\t\tbuf.WriteString(\"\\n\")\n\t\t\t}\n\t\t\treturn buf.String()\n\t\t}\n\t\tone = fn(addUsers.Changes)\n\t\ttwo = fn(addUsers2.Changes)\n\t)\n\n\tp := t.TempDir()\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"1.sql\"), []byte(one), 0644))\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"2.sql\"), []byte(two), 0644))\n\n\trequire.NoError(t, exec.Command(\n\t\texecPath(t),\n\t\t\"migrate\", \"hash\",\n\t\t\"--dir\", \"file://\"+p,\n\t).Run())\n\n\t// All versions - must contain all migration files.\n\tout, err := exec.Command(\n\t\texecPath(t),\n\t\t\"schema\", \"apply\",\n\t\t\"-u\", t.url(dbname),\n\t\t\"--to\", \"file://\"+p,\n\t\t\"--dev-url\", t.url(devname),\n\t\t\"--dry-run\",\n\t\t\"--format\", \"{{ range $c := .Changes.Pending }}{{ println $c.Cmd }}{{ end }}\",\n\t).CombinedOutput()\n\trequire.NoError(t, err)\n\t// Normalize oss/ent output.\n\tout = bytes.ReplaceAll(out, []byte(\";\"), []byte(\"\"))\n\trequire.Contains(t, string(out), one)\n\trequire.Contains(t, string(out), two)\n\n\t// One version - must contain only file one.\n\tout, err = exec.Command(\n\t\texecPath(t),\n\t\t\"schema\", \"apply\",\n\t\t\"-u\", t.url(dbname),\n\t\t\"--to\", \"file://\"+p+\"?version=1\",\n\t\t\"--dev-url\", t.url(devname),\n\t\t\"--dry-run\",\n\t\t\"--format\", \"{{ range $c := .Changes.Pending }}{{ println $c.Cmd }}{{ end }}\",\n\t).CombinedOutput()\n\trequire.NoError(t, err)\n\t// Normalize oss/ent output.\n\tout = bytes.ReplaceAll(out, []byte(\";\"), []byte(\"\"))\n\trequire.Contains(t, string(out), one)\n\trequire.NotContains(t, string(out), two)\n}\n\nfunc testCLISchemaDiff(t T, url string) {\n\tt.dropTables(\"users\")\n\tcmd := exec.Command(execPath(t),\n\t\t\"schema\",\n\t\t\"diff\",\n\t\t\"--from\",\n\t\turl,\n\t\t\"--to\",\n\t\turl,\n\t)\n\tstdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)\n\tcmd.Stderr = stderr\n\tcmd.Stdout = stdout\n\trequire.NoError(t, cmd.Run(), stderr.String(), stdout.String())\n\trequire.Empty(t, stderr.String(), stderr.String())\n\trequire.Contains(t, stdout.String(), \"Schemas are synced, no changes to be made.\")\n}\n\nfunc ensureNoChange(t T, tables ...*schema.Table) {\n\trealm := t.loadRealm()\n\trequire.Equal(t, len(realm.Schemas[0].Tables), len(tables))\n\tfor i := range tables {\n\t\ttt, ok := realm.Schemas[0].Table(tables[i].Name)\n\t\trequire.True(t, ok)\n\t\tchanges := t.diff(tt, tables[i])\n\t\trequire.Emptyf(t, changes, \"changes should be empty for table %s, but instead was %#v\", tt.Name, changes)\n\t}\n}\n\nfunc testAdvisoryLock(t *testing.T, l schema.Locker) {\n\tt.Run(\"One\", func(t *testing.T) {\n\t\tunlock, err := l.Lock(context.Background(), \"migrate\", 0)\n\t\trequire.NoError(t, err)\n\t\t_, err = l.Lock(context.Background(), \"migrate\", 0)\n\t\trequire.Equal(t, schema.ErrLocked, err)\n\t\trequire.NoError(t, unlock())\n\t})\n\tt.Run(\"Multi\", func(t *testing.T) {\n\t\tvar unlocks []schema.UnlockFunc\n\t\tfor _, name := range []string{\"a\", \"b\", \"c\"} {\n\t\t\tunlock, err := l.Lock(context.Background(), name, 0)\n\t\t\trequire.NoError(t, err)\n\t\t\tunlocks = append(unlocks, unlock)\n\t\t}\n\t\tfor _, unlock := range unlocks {\n\t\t\trequire.NoError(t, unlock())\n\t\t}\n\t})\n}\n\nfunc testExecutor(t T) {\n\tusersT, postsT := t.users(), t.posts()\n\tpetsT := &schema.Table{\n\t\tName:   \"pets\",\n\t\tSchema: usersT.Schema,\n\t\tColumns: []*schema.Column{\n\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t{Name: \"owner_id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}, Null: true}},\n\t\t},\n\t}\n\tpetsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}\n\tpetsT.ForeignKeys = []*schema.ForeignKey{\n\t\t{Symbol: \"owner_id\", Table: petsT, Columns: petsT.Columns[1:], RefTable: usersT, RefColumns: usersT.Columns[:1]},\n\t}\n\tif tt, ok := t.(interface {\n\t\tpets(_, _ *schema.Table) *schema.Table\n\t}); ok {\n\t\tpetsT = tt.pets(usersT, postsT)\n\t}\n\tt.dropTables(petsT.Name, postsT.Name, usersT.Name)\n\tt.Cleanup(func() {\n\t\tt.revisionsStorage().(*rrw).clean()\n\t})\n\n\tdir, err := migrate.NewLocalDir(t.TempDir())\n\trequire.NoError(t, err)\n\tf, err := migrate.NewTemplateFormatter(\n\t\ttemplate.Must(template.New(\"\").Parse(\"{{ .Name }}.sql\")),\n\t\ttemplate.Must(template.New(\"\").Parse(\n\t\t\t`{{ range .Changes }}{{ with .Comment }}-- {{ println . }}{{ end }}{{ printf \"%s;\\n\" .Cmd }}{{ end }}`,\n\t\t)),\n\t)\n\trequire.NoError(t, err)\n\tpl := migrate.NewPlanner(t.driver(), dir, migrate.PlanFormat(f))\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, pl.WritePlan(plan(t, \"1_users\", &schema.AddTable{T: usersT})))\n\trequire.NoError(t, pl.WritePlan(plan(t, \"2_posts\", &schema.AddTable{T: postsT})))\n\trequire.NoError(t, pl.WritePlan(plan(t, \"3_pets\", &schema.AddTable{T: petsT})))\n\n\tex, err := migrate.NewExecutor(t.driver(), dir, t.revisionsStorage())\n\trequire.NoError(t, err)\n\trequire.NoError(t, ex.ExecuteN(context.Background(), 2)) // usersT and postsT\n\trequire.Len(t, *t.revisionsStorage().(*rrw), 2)\n\tensureNoChange(t, postsT, usersT)\n\trequire.NoError(t, ex.ExecuteN(context.Background(), 1)) // petsT\n\trequire.Len(t, *t.revisionsStorage().(*rrw), 3)\n\tensureNoChange(t, petsT, postsT, usersT)\n\n\trequire.ErrorIs(t, ex.ExecuteN(context.Background(), 1), migrate.ErrNoPendingFiles)\n}\n\nfunc plan(t T, name string, changes ...schema.Change) *migrate.Plan {\n\tp, err := t.driver().PlanChanges(context.Background(), name, changes)\n\trequire.NoError(t, err)\n\treturn p\n}\n\ntype rrw []*migrate.Revision\n\nfunc (r *rrw) Ident() *migrate.TableIdent {\n\treturn &migrate.TableIdent{}\n}\n\nfunc (r *rrw) WriteRevision(_ context.Context, rev *migrate.Revision) error {\n\tfor i, rev2 := range *r {\n\t\tif rev2.Version == rev.Version {\n\t\t\t(*r)[i] = rev\n\t\t\treturn nil\n\t\t}\n\t}\n\t*r = append(*r, rev)\n\treturn nil\n}\n\nfunc (r *rrw) ReadRevision(_ context.Context, v string) (*migrate.Revision, error) {\n\tfor _, rev := range *r {\n\t\tif rev.Version == v {\n\t\t\treturn rev, nil\n\t\t}\n\t}\n\treturn nil, migrate.ErrRevisionNotExist\n}\n\nfunc (r *rrw) DeleteRevision(_ context.Context, v string) error {\n\ti := -1\n\tfor j, r := range *r {\n\t\tif r.Version == v {\n\t\t\ti = j\n\t\t\tbreak\n\t\t}\n\t}\n\tif i == -1 {\n\t\treturn nil\n\t}\n\tcopy((*r)[i:], (*r)[i+1:])\n\t*r = (*r)[:len(*r)-1]\n\treturn nil\n}\n\nfunc (r *rrw) ReadRevisions(context.Context) ([]*migrate.Revision, error) {\n\treturn *r, nil\n}\n\nfunc (r *rrw) clean() {\n\t*r = []*migrate.Revision{}\n}\n\nvar (\n\tbuildFlags []string\n\t_          migrate.RevisionReadWriter = (*rrw)(nil)\n\tbuildOnce  sync.Once\n)\n\nfunc cliPath(t testing.TB) string {\n\tpath := filepath.Join(os.TempDir(), \"atlas\")\n\tbuildOnce.Do(func() {\n\t\targs := append([]string{\"build\"}, buildFlags...)\n\t\targs = append(args, \"-o\", path, \"ariga.io/atlas/cmd/atlas\")\n\t\tout, err := exec.Command(\"go\", args...).CombinedOutput()\n\t\trequire.NoError(t, err, string(out))\n\t})\n\treturn path\n}\n\nfunc evalBytes(b []byte, v any, ev schemahcl.Evaluator) error {\n\tp := hclparse.NewParser()\n\tif _, diag := p.ParseHCL(b, \"\"); diag.HasErrors() {\n\t\treturn diag\n\t}\n\treturn ev.Eval(p, v, nil)\n}\n"
  },
  {
    "path": "internal/integration/mysql_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage integration\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/mysql\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t_ \"github.com/go-sql-driver/mysql\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype myTest struct {\n\t*testing.T\n\tdb      *sql.DB\n\tdrv     migrate.Driver\n\trrw     migrate.RevisionReadWriter\n\tversion string\n\tport    int\n\tonce    sync.Once\n}\n\nvar myTests = map[string]*myTest{\n\t\"mysql56\":  {port: 3306},\n\t\"mysql57\":  {port: 3307},\n\t\"mysql8\":   {port: 3308},\n\t\"maria107\": {port: 4306},\n\t\"maria102\": {port: 4307},\n\t\"maria103\": {port: 4308},\n}\n\nfunc myRun(t *testing.T, fn func(*myTest)) {\n\tfor version, tt := range myTests {\n\t\tif flagVersion == \"\" || flagVersion == version {\n\t\t\tt.Run(version, func(t *testing.T) {\n\t\t\t\ttt.once.Do(func() {\n\t\t\t\t\ttt.version = version\n\t\t\t\t\ttt.rrw = &rrw{}\n\t\t\t\t\tc, err := sqlclient.Open(context.Background(), fmt.Sprintf(\"mysql://root:pass@localhost:%d/test?parseTime=true\", tt.port))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\ttt.drv, tt.db = c.Driver, c.DB\n\t\t\t\t\t// Close connection after all tests have been run.\n\t\t\t\t\tdbs = append(dbs, tt.db)\n\t\t\t\t})\n\t\t\t\ttt := &myTest{T: t, db: tt.db, drv: tt.drv, version: version, port: tt.port, rrw: tt.rrw}\n\t\t\t\tfn(tt)\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc TestMySQL_Executor(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\ttestExecutor(t)\n\t})\n}\n\nfunc TestMySQL_AddDropTable(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\ttestAddDrop(t)\n\t})\n}\n\nfunc TestMySQL_Relation(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\ttestRelation(t)\n\t})\n}\n\nfunc TestMySQL_AddIndexedColumns(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\tusersT := &schema.Table{\n\t\t\tName:    \"users\",\n\t\t\tColumns: []*schema.Column{{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}}},\n\t\t}\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tt.dropTables(usersT.Name)\n\t\tusersT.Columns = append(usersT.Columns, &schema.Column{\n\t\t\tName:    \"a\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.RawExpr{X: \"10\"},\n\t\t}, &schema.Column{\n\t\t\tName:    \"b\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.RawExpr{X: \"10\"},\n\t\t}, &schema.Column{\n\t\t\tName:    \"c\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.RawExpr{X: \"10\"},\n\t\t})\n\t\tparts := usersT.Columns[len(usersT.Columns)-3:]\n\t\tusersT.Indexes = append(usersT.Indexes, &schema.Index{\n\t\t\tUnique: true,\n\t\t\tName:   \"a_b_c_unique\",\n\t\t\tParts:  []*schema.IndexPart{{C: parts[0]}, {C: parts[1]}, {C: parts[2]}},\n\t\t})\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.NotEmpty(t, changes, \"usersT contains 2 new columns and 1 new index\")\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\n\t\t// In MySQL, dropping a column should remove it from the key.\n\t\t// However, on MariaDB an explicit DROP/ADD INDEX is required.\n\t\tif t.mariadb() {\n\t\t\tidx, ok := usersT.Index(\"a_b_c_unique\")\n\t\t\trequire.True(t, ok)\n\t\t\tidx.Parts = idx.Parts[:len(idx.Parts)-1]\n\t\t}\n\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, t.loadUsers())\n\n\t\t// Dropping a column from both table and index.\n\t\tusersT = t.loadUsers()\n\t\tidx, ok := usersT.Index(\"a_b_c_unique\")\n\t\trequire.True(t, ok)\n\t\trequire.Len(t, idx.Parts, 2)\n\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\tidx.Parts = idx.Parts[:len(idx.Parts)-1]\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 2)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, t.loadUsers())\n\n\t\t// Dropping a column should remove\n\t\t// single-column keys as well.\n\t\tusersT = t.loadUsers()\n\t\tidx, ok = usersT.Index(\"a_b_c_unique\")\n\t\trequire.True(t, ok)\n\t\trequire.Len(t, idx.Parts, 1)\n\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 1)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, t.loadUsers())\n\t\tidx, ok = t.loadUsers().Index(\"a_b_c_unique\")\n\t\trequire.False(t, ok)\n\t})\n}\n\nfunc TestMySQL_AddColumns(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\tusersT := t.users()\n\t\tt.dropTables(usersT.Name)\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tusersT.Columns = append(\n\t\t\tusersT.Columns,\n\t\t\t&schema.Column{Name: \"a\", Type: &schema.ColumnType{Raw: \"tinyblob\", Type: &schema.BinaryType{T: \"tinyblob\"}}},\n\t\t\t&schema.Column{Name: \"b\", Type: &schema.ColumnType{Raw: \"mediumblob\", Type: &schema.BinaryType{T: \"mediumblob\"}}},\n\t\t\t&schema.Column{Name: \"c\", Type: &schema.ColumnType{Raw: \"blob\", Type: &schema.BinaryType{T: \"blob\"}}},\n\t\t\t&schema.Column{Name: \"d\", Type: &schema.ColumnType{Raw: \"longblob\", Type: &schema.BinaryType{T: \"longblob\"}}},\n\t\t\t&schema.Column{Name: \"e\", Type: &schema.ColumnType{Raw: \"binary\", Type: &schema.BinaryType{T: \"binary\"}}},\n\t\t\t&schema.Column{Name: \"f\", Type: &schema.ColumnType{Raw: \"varbinary(255)\", Type: &schema.BinaryType{T: \"varbinary(255)\"}}, Default: &schema.Literal{V: \"foo\"}},\n\t\t\t&schema.Column{Name: \"g\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar\", Size: 255}}},\n\t\t\t&schema.Column{Name: \"h\", Type: &schema.ColumnType{Raw: \"varchar(255)\", Type: &schema.StringType{T: \"varchar(255)\"}}},\n\t\t\t&schema.Column{Name: \"i\", Type: &schema.ColumnType{Raw: \"tinytext\", Type: &schema.StringType{T: \"tinytext\"}}},\n\t\t\t&schema.Column{Name: \"j\", Type: &schema.ColumnType{Raw: \"mediumtext\", Type: &schema.StringType{T: \"mediumtext\"}}},\n\t\t\t&schema.Column{Name: \"k\", Type: &schema.ColumnType{Raw: \"text\", Type: &schema.StringType{T: \"text\"}}},\n\t\t\t&schema.Column{Name: \"l\", Type: &schema.ColumnType{Raw: \"longtext\", Type: &schema.StringType{T: \"longtext\"}}},\n\t\t\t&schema.Column{Name: \"m\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\", Precision: 10, Scale: 6}}},\n\t\t\t&schema.Column{Name: \"m1\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\"}}},\n\t\t\t&schema.Column{Name: \"m2\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\", Precision: 2}}},\n\t\t\t&schema.Column{Name: \"n\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 10, Scale: 2}}},\n\t\t\t&schema.Column{Name: \"n1\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\"}}},\n\t\t\t&schema.Column{Name: \"n2\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 2}}},\n\t\t\t&schema.Column{Name: \"o\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"float\", Precision: 2}}},\n\t\t\t&schema.Column{Name: \"p\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"double\", Precision: 14}}},\n\t\t\t&schema.Column{Name: \"q\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"real\", Precision: 14}}},\n\t\t\t&schema.Column{Name: \"r\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t&schema.Column{Name: \"s\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t&schema.Column{Name: \"t\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"smallint\"}}},\n\t\t\t&schema.Column{Name: \"u\", Type: &schema.ColumnType{Type: &schema.EnumType{T: \"enum\", Values: []string{\"a\", \"b\", \"c\"}}}},\n\t\t\t&schema.Column{Name: \"v\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"char(36)\"}}},\n\t\t\t&schema.Column{Name: \"x\", Type: &schema.ColumnType{Type: &schema.SpatialType{T: \"line\"}}},\n\t\t\t&schema.Column{Name: \"y\", Type: &schema.ColumnType{Type: &schema.SpatialType{T: \"point\"}}},\n\t\t\t&schema.Column{Name: \"z\", Type: &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp\"}}, Default: &schema.RawExpr{X: \"CURRENT_TIMESTAMP\"}},\n\t\t)\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 28)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestMySQL_ColumnInt(t *testing.T) {\n\tt.Run(\"ChangeType\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}}},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tfor _, typ := range []string{\"tinyint\", \"smallint\", \"mediumint\", \"bigint\"} {\n\t\t\t\tusersT.Columns[0].Type.Type = &schema.IntegerType{T: typ}\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t}\n\t\t})\n\t})\n\n\tt.Run(\"ChangeDefault\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}, Default: &schema.RawExpr{X: \"1\"}}},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t\tfor _, x := range []string{\"2\", \"'3'\", \"10.1\"} {\n\t\t\t\tusersT.Columns[0].Default.(*schema.RawExpr).X = x\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t}\n\t\t})\n\t})\n}\n\nfunc TestMySQL_ColumnString(t *testing.T) {\n\tt.Run(\"ChangeType\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(20)\"}}}},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tfor _, typ := range []string{\"varchar(255)\", \"char(120)\", \"tinytext\", \"mediumtext\", \"longtext\"} {\n\t\t\t\tusersT.Columns[0].Type.Type = &schema.StringType{T: typ}\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t}\n\t\t})\n\t})\n\n\tt.Run(\"AddWithDefault\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(255)\"}}, Default: &schema.RawExpr{X: \"hello\"}},\n\t\t\t\t\t{Name: \"b\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"char(255)\"}}, Default: &schema.RawExpr{X: \"'world'\"}},\n\t\t\t\t},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"ChangeDefault\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(255)\"}}, Default: &schema.RawExpr{X: \"hello\"}}},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t\tfor _, x := range []string{\"2\", \"'3'\", \"'world'\"} {\n\t\t\t\tusersT.Columns[0].Default.(*schema.RawExpr).X = x\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t}\n\t\t})\n\t})\n}\n\nfunc TestMySQL_ColumnBool(t *testing.T) {\n\tt.Run(\"Add\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}},\n\t\t\t\t\t{Name: \"b\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}}},\n\t\t\t\t\t{Name: \"c\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"tinyint\"}}},\n\t\t\t\t\t{Name: \"d\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"tinyint(1)\"}}},\n\t\t\t\t},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"AddWithDefault\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"1\"}},\n\t\t\t\t\t{Name: \"b\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"0\"}},\n\t\t\t\t\t{Name: \"c\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"'1'\"}},\n\t\t\t\t\t{Name: \"d\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"'0'\"}},\n\t\t\t\t\t{Name: \"e\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"true\"}},\n\t\t\t\t\t{Name: \"f\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"false\"}},\n\t\t\t\t\t{Name: \"g\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"TRUE\"}},\n\t\t\t\t\t{Name: \"h\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"FALSE\"}},\n\t\t\t\t},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"ChangeDefault\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"1\"}},\n\t\t\t\t},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t\t// Change default from \"true\" to \"false\" to \"true\".\n\t\t\tfor _, x := range []string{\"false\", \"true\"} {\n\t\t\t\tusersT.Columns[0].Default.(*schema.RawExpr).X = x\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t}\n\t\t})\n\t})\n\n\tt.Run(\"ChangeNull\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}, Null: true}},\n\t\t\t\t},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t\tusersT.Columns[0].Type.Null = false\n\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 1)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n}\n\nfunc TestMySQL_ColumnCheck(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\t// Checks are not supported in all versions.\n\t\tif t.version == \"mysql56\" || t.version == \"mysql57\" {\n\t\t\tt.Skip()\n\t\t}\n\t\tusersT := &schema.Table{\n\t\t\tName:  \"users\",\n\t\t\tAttrs: []schema.Attr{schema.NewCheck().SetName(\"users_c_check\").SetExpr(\"c > 5\")},\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t{Name: \"c\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t},\n\t\t}\n\t\tt.dropTables(usersT.Name)\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestMySQL_ForeignKey(t *testing.T) {\n\tt.Run(\"ChangeAction\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT, postsT := t.users(), t.posts()\n\t\t\tt.dropTables(postsT.Name, usersT.Name)\n\t\t\tt.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})\n\t\t\tensureNoChange(t, postsT, usersT)\n\n\t\t\tpostsT = t.loadPosts()\n\t\t\tfk, ok := postsT.ForeignKey(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tfk.OnUpdate = schema.SetNull\n\t\t\tfk.OnDelete = schema.Cascade\n\t\t\tchanges := t.diff(t.loadPosts(), postsT)\n\t\t\trequire.Len(t, changes, 1)\n\t\t\tmodifyF, ok := changes[0].(*schema.ModifyForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)\n\n\t\t\tt.migrate(&schema.ModifyTable{T: postsT, Changes: changes})\n\t\t\tensureNoChange(t, postsT, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"UnsetNull\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT, postsT := t.users(), t.posts()\n\t\t\tt.dropTables(postsT.Name, usersT.Name)\n\t\t\tfk, ok := postsT.ForeignKey(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tfk.OnDelete = schema.SetNull\n\t\t\tfk.OnUpdate = schema.SetNull\n\t\t\tt.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})\n\t\t\tensureNoChange(t, postsT, usersT)\n\n\t\t\tpostsT = t.loadPosts()\n\t\t\tc, ok := postsT.Column(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tc.Type.Null = false\n\t\t\tfk, ok = postsT.ForeignKey(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tfk.OnUpdate = schema.NoAction\n\t\t\tfk.OnDelete = schema.NoAction\n\t\t\tchanges := t.diff(t.loadPosts(), postsT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\tmodifyC, ok := changes[0].(*schema.ModifyColumn)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyC.Change == schema.ChangeNull)\n\t\t\tmodifyF, ok := changes[1].(*schema.ModifyForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)\n\n\t\t\tt.migrate(&schema.ModifyTable{T: postsT, Changes: changes})\n\t\t\tensureNoChange(t, postsT, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"AddDrop\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tusersT := t.users()\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tensureNoChange(t, usersT)\n\n\t\t\t// Add foreign key.\n\t\t\tusersT.Columns = append(usersT.Columns, &schema.Column{\n\t\t\t\tName: \"spouse_id\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\t})\n\t\t\tusersT.ForeignKeys = append(usersT.ForeignKeys, &schema.ForeignKey{\n\t\t\t\tSymbol:     \"spouse_id\",\n\t\t\t\tTable:      usersT,\n\t\t\t\tColumns:    usersT.Columns[len(usersT.Columns)-1:],\n\t\t\t\tRefTable:   usersT,\n\t\t\t\tRefColumns: usersT.Columns[:1],\n\t\t\t\tOnDelete:   schema.NoAction,\n\t\t\t})\n\n\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\taddC, ok := changes[0].(*schema.AddColumn)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, \"spouse_id\", addC.C.Name)\n\t\t\taddF, ok := changes[1].(*schema.AddForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, \"spouse_id\", addF.F.Symbol)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\n\t\t\t// Drop foreign keys.\n\t\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\t\tusersT.ForeignKeys = usersT.ForeignKeys[:len(usersT.ForeignKeys)-1]\n\t\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n}\n\nfunc TestMySQL_AdvisoryLock(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\ttestAdvisoryLock(t.T, t.drv.(schema.Locker))\n\t})\n}\n\nfunc TestMySQL_HCL(t *testing.T) {\n\tfull := `\nschema \"test\" {\n}\ntable \"users\" {\n\tschema = schema.test\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tprimary_key {\n\t\tcolumns = [table.users.column.id]\n\t}\n}\ntable \"posts\" {\n\tschema = schema.test\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tcolumn \"author_id\" {\n\t\ttype = int\n\t}\n\tforeign_key \"author\" {\n\t\tcolumns = [\n\t\t\ttable.posts.column.author_id,\n\t\t]\n\t\tref_columns = [\n\t\t\ttable.users.column.id,\n\t\t]\n\t}\n\tprimary_key {\n\t\tcolumns = [table.users.column.id]\n\t}\n}\n`\n\tempty := `\nschema \"test\" {\n}\n`\n\tmyRun(t, func(t *myTest) {\n\t\ttestHCLIntegration(t, full, empty)\n\t})\n}\n\nfunc TestMySQL_Snapshot(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\tdb, err := sql.Open(\"mysql\", fmt.Sprintf(\"root:pass@tcp(localhost:%d)/\", t.port))\n\t\trequire.NoError(t, err)\n\t\tt.Cleanup(func() {\n\t\t\trequire.NoError(t, db.Close())\n\t\t})\n\t\tdrv, err := mysql.Open(db)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = drv.Snapshot(context.Background())\n\t\trequire.ErrorAs(t, err, new(*migrate.NotCleanError))\n\n\t\tr, err := t.driver().InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\t\tMode: schema.InspectSchemas | schema.InspectTables,\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trestore, err := t.driver().Snapshot(context.Background())\n\t\trequire.NoError(t, err) // connected to test schema\n\t\tt.migrate(&schema.AddTable{T: schema.NewTable(\"my_table\").AddColumns(\n\t\t\tschema.NewIntColumn(\"col_1\", \"integer\").SetNull(true),\n\t\t\tschema.NewIntColumn(\"col_2\", \"bigint\"),\n\t\t)})\n\t\tt.Cleanup(func() {\n\t\t\tt.dropTables(\"my_table\")\n\t\t})\n\t\trequire.NoError(t, restore(context.Background()))\n\t\tr1, err := t.driver().InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\t\tMode: schema.InspectSchemas | schema.InspectTables,\n\t\t})\n\t\trequire.NoError(t, err)\n\t\tdiff, err := t.driver().RealmDiff(r1, r)\n\t\trequire.NoError(t, err)\n\t\trequire.Zero(t, diff)\n\t})\n}\n\nfunc TestMySQL_CLI_MigrateApplyBC(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\ttestCLIMigrateApplyBC(t, \"mysql\")\n\t})\n}\n\nfunc TestMySQL_CLI_MigrateApplyLock(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\tt.dropSchemas(\"mysqlock\")\n\t\tt.migrate(&schema.AddSchema{S: schema.New(\"mysqlock\")})\n\t\tvar (\n\t\t\tb  atomic.Bool\n\t\t\twg sync.WaitGroup\n\t\t)\n\t\tfor i := 0; i < 5; i++ {\n\t\t\twg.Add(1)\n\t\t\tgo func(i int) {\n\t\t\t\tdefer wg.Done()\n\t\t\t\tout, err := exec.Command(\n\t\t\t\t\texecPath(t),\n\t\t\t\t\t\"migrate\", \"apply\",\n\t\t\t\t\t\"--dir\", \"file://testdata/migrations/mysqlock\",\n\t\t\t\t\t\"--url\", t.url(\"mysqlock\"),\n\t\t\t\t).CombinedOutput()\n\t\t\t\trequire.NoError(t, err, string(out))\n\t\t\t\tswitch {\n\t\t\t\t// Nop.\n\t\t\t\tcase err == nil && strings.HasPrefix(string(out), \"No migration files to execute\"):\n\t\t\t\t// Successful run.\n\t\t\t\tcase err == nil && strings.HasPrefix(string(out), \"Migrating to version 3\"):\n\t\t\t\t\tif b.Swap(true) {\n\t\t\t\t\t\tt.Errorf(\"migration ran twice: %s\", out)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}(i)\n\t\t}\n\t\twg.Wait()\n\t\trequire.True(t, b.Load(), \"Migration should run successfully exactly once\")\n\t})\n}\n\nfunc TestMySQL_CLI(t *testing.T) {\n\th := `\n\t\t\tschema \"test\" {\n\t\t\t\tcharset   = \"%s\"\n\t\t\t\tcollation = \"%s\"\n\t\t\t}\n\t\t\ttable \"users\" {\n\t\t\t\tschema = schema.test\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = int\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [table.users.column.id]\n\t\t\t\t}\n\t\t\t}`\n\tt.Run(\"SchemaInspect\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLISchemaInspect(t, fmt.Sprintf(h, charset.V, collate.V), t.url(\"test\"), mysql.EvalHCL)\n\t\t})\n\t})\n\tt.Run(\"SchemaApply\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLISchemaApply(t, fmt.Sprintf(h, charset.V, collate.V), t.url(\"test\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyWithVars\", func(t *testing.T) {\n\t\th := `\nvariable \"tenant\" {\n\ttype = string\n}\nschema \"tenant\" {\n\tname = var.tenant\n}\ntable \"users\" {\n\tschema = schema.tenant\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n}\n`\n\t\tmyRun(t, func(t *myTest) {\n\t\t\ttestCLISchemaApply(t, h, t.url(\"test\"), \"--var\", \"tenant=test\")\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyDryRun\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLISchemaApplyDry(t, fmt.Sprintf(h, charset.V, collate.V), t.url(\"test\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaDiffRun\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\ttestCLISchemaDiff(t, t.url(\"test\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyAutoApprove\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLISchemaApplyAutoApprove(t, fmt.Sprintf(h, charset.V, collate.V), t.url(\"test\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyFromMigrationDir\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\ttestCLISchemaApplyFromMigrationDir(t)\n\t\t})\n\t})\n}\n\nfunc TestMySQL_CLI_MultiSchema(t *testing.T) {\n\th := `\n\t\t\tschema \"test\" {\n\t\t\t\tcharset   = \"%s\"\n\t\t\t\tcollation = \"%s\"\n\t\t\t}\n\t\t\ttable \"test\" \"users\" {\n\t\t\t\tschema = schema.test\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = int\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [column.id]\n\t\t\t\t}\n\t\t\t}\n\t\t\tschema \"test2\" {\n\t\t\t\tcharset   = \"%s\"\n\t\t\t\tcollation = \"%s\"\n\t\t\t}\n\t\t\ttable \"test2\" \"users\" {\n\t\t\t\tschema = schema.test2\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = int\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [column.id]\n\t\t\t\t}\n\t\t\t}`\n\tt.Run(\"SchemaInspect\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tt.dropSchemas(\"test2\")\n\t\t\tt.dropTables(\"users\")\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLIMultiSchemaInspect(t, fmt.Sprintf(h, charset.V, collate.V, charset.V, collate.V), t.url(\"\"), []string{\"test\", \"test2\"}, mysql.EvalHCL)\n\t\t})\n\t})\n\tt.Run(\"SchemaApply\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tt.dropSchemas(\"test2\")\n\t\t\tt.dropTables(\"users\")\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLIMultiSchemaApply(t, fmt.Sprintf(h, charset.V, collate.V, charset.V, collate.V), t.url(\"\"), []string{\"test\", \"test2\"}, mysql.EvalHCL)\n\t\t})\n\t})\n}\n\nfunc TestMySQL_HCL_Realm(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\tt.dropSchemas(\"second\")\n\t\trealm := t.loadRealm()\n\t\thcl, err := mysql.MarshalHCL(realm)\n\t\trequire.NoError(t, err)\n\t\twa := string(hcl) + `\nschema \"second\" {\n}\n`\n\t\tt.applyRealmHcl(wa)\n\t\trealm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\t\tMode: schema.InspectSchemas | schema.InspectTables,\n\t\t})\n\t\trequire.NoError(t, err)\n\t\t_, ok := realm.Schema(\"test\")\n\t\trequire.True(t, ok)\n\t\t_, ok = realm.Schema(\"second\")\n\t\trequire.True(t, ok)\n\t})\n}\n\nfunc TestMySQL_HCL_ForeignKeyCrossSchema(t *testing.T) {\n\tconst expected = `table \"credit_cards\" {\n  schema = schema.financial\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"user_id\" {\n    null = false\n    type = int\n  }\n  primary_key {\n    columns = [column.id]\n  }\n  foreign_key \"user_id_fkey\" {\n    columns     = [column.user_id]\n    ref_columns = [table.users.users.column.id]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n  index \"user_id_fkey\" {\n    columns = [column.user_id]\n  }\n}\ntable \"financial\" \"users\" {\n  schema = schema.financial\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\ntable \"users\" \"users\" {\n  schema = schema.users\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"email\" {\n    null = false\n    type = varchar(255)\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\nschema \"financial\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}\nschema \"users\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}\n`\n\tmyRun(t, func(t *myTest) {\n\t\tt.dropSchemas(\"financial\", \"users\")\n\t\trealm := t.loadRealm()\n\t\thcl, err := mysql.MarshalHCL(realm)\n\t\trequire.NoError(t, err)\n\t\tt.applyRealmHcl(string(hcl) + \"\\n\" + expected)\n\t\trealm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\t\tMode:    schema.InspectSchemas | schema.InspectTables,\n\t\t\tSchemas: []string{\"users\", \"financial\"},\n\t\t})\n\t\trequire.NoError(t, err)\n\t\tactual, err := mysql.MarshalHCL(realm)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expected, string(actual))\n\t})\n}\n\nfunc TestMySQL_DefaultsHCL(t *testing.T) {\n\tn := \"atlas_defaults\"\n\tmyRun(t, func(t *myTest) {\n\t\tddl := `\ncreate table atlas_defaults\n(\n\tstring varchar(255) default \"hello_world\",\n\tquoted varchar(100) default 'never say \"never\"',\n\ttBit bit(10) default b'10101',\n\tts timestamp default CURRENT_TIMESTAMP,\n\tnumber int default 42\n)\n`\n\t\tt.dropTables(n)\n\t\t_, err := t.db.Exec(ddl)\n\t\trequire.NoError(t, err)\n\t\trealm := t.loadRealm()\n\t\tspec, err := mysql.MarshalHCL(realm.Schemas[0])\n\t\trequire.NoError(t, err)\n\t\tvar s schema.Realm\n\t\terr = mysql.EvalHCLBytes(spec, &s, nil)\n\t\trequire.NoError(t, err)\n\t\tt.dropTables(n)\n\t\tt.applyHcl(string(spec))\n\t\tensureNoChange(t, realm.Schemas[0].Tables[0])\n\t})\n}\n\nfunc TestMySQL_Sanity(t *testing.T) {\n\tn := \"atlas_types_sanity\"\n\tt.Run(\"Common\", func(t *testing.T) {\n\t\tddl := `\ncreate table atlas_types_sanity\n(\n    tBit                        bit(10)              default b'100'                                              null,\n    tInt                        int(10)              default 4                                               not null,\n    tTinyInt                    tinyint(10)          default 8                                                   null,\n    tSmallInt                   smallint(10)         default 2                                                   null,\n    tMediumInt                  mediumint(10)        default 11                                                  null,\n    tBigInt                     bigint(10)           default 4                                                   null,\n    tDecimal                    decimal              default 4                                                   null,\n    tNumeric                    numeric              default 4                                               not null,\n    tFloat                      float(10, 0)         default 4                                                   null,\n    tDouble                     double(10, 0)        default 4                                                   null,\n    tReal                       double(10, 0)        default 4                                                   null,\n    tTimestamp                  timestamp            default CURRENT_TIMESTAMP                                   null,\n    tTimestampFraction          timestamp(6)         default CURRENT_TIMESTAMP(6)                                null,\n    tTimestampOnUpdate          timestamp            default CURRENT_TIMESTAMP    ON UPDATE CURRENT_TIMESTAMP    null,\n    tTimestampFractionOnUpdate  timestamp(6)         default CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) null,\n    tDate                       date                                                                             null,\n    tTime                       time                                                                             null,\n    tDateTime                   datetime                                                                         null,\n    tYear                       year                                                                             null,\n    tVarchar                    varchar(10)          default 'Titan'                                             null,\n    tChar                       char(25)             default 'Olimpia'                                       not null,\n    tVarBinary                  varbinary(30)        default 'Titan'                                             null,\n    tBinary                     binary(5)            default 'Titan'                                             null,\n    tBlob                       blob(5)              default                                                     null,\n    tTinyBlob                   tinyblob                                                                         null,\n    tMediumBlob                 mediumblob           default                                                     null,\n    tLongBlob                   longblob             default                                                     null,\n    tText                       text(13)             default                                                     null,\n    tTinyText                   tinytext             default                                                     null,\n    tMediumText                 mediumtext           default                                                     null,\n    tLongText                   longtext             default                                                     null,\n    tEnum                       enum('a','b')        default                                                     null,\n    tSet                        set('a','b')         default                                                     null,\n    tGeometry                   geometry             default                                                     null,\n    tPoint                      point                default                                                     null,\n    tMultiPoint                 multipoint           default                                                     null,\n    tLineString                 linestring           default                                                     null,\n    tMultiLineString            multilinestring      default                                                     null,\n    tPolygon                    polygon              default                                                     null,\n    tMultiPolygon               multipolygon         default                                                     null,\n    tGeometryCollection         geometrycollection   default                                                     null\n) CHARSET = latin1 COLLATE latin1_swedish_ci;\n`\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tt.dropTables(n)\n\t\t\t_, err := t.db.Exec(ddl)\n\t\t\trequire.NoError(t, err)\n\t\t\trealm := t.loadRealm()\n\t\t\trequire.Len(t, realm.Schemas, 1)\n\t\t\tts, ok := realm.Schemas[0].Table(n)\n\t\t\trequire.True(t, ok)\n\t\t\texpected := schema.Table{\n\t\t\t\tName: n,\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t&mysql.Engine{V: \"InnoDB\", Default: true},\n\t\t\t\t},\n\t\t\t\tSchema: realm.Schemas[0],\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"tBit\",\n\t\t\t\t\t\tType:    &schema.ColumnType{Type: &mysql.BitType{T: \"bit\", Size: 10}, Raw: \"bit(10)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"b'100'\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tInt\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"int\"}, \"int(10)\"), Null: false},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTinyInt\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"tinyint\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"tinyint\"}, \"tinyint(10)\"), Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"8\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tSmallInt\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"smallint\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"smallint\"}, \"smallint(10)\"), Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"2\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tMediumInt\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"mediumint\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"mediumint\"}, \"mediumint(10)\"), Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"11\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tBigInt\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"bigint\"}, \"bigint(10)\"), Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tDecimal\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\", Precision: 10},\n\t\t\t\t\t\t\tRaw: \"decimal(10,0)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tNumeric\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\", Precision: 10},\n\t\t\t\t\t\t\tRaw: \"decimal(10,0)\", Null: false},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tFloat\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.FloatType{T: \"float\", Precision: 10},\n\t\t\t\t\t\t\tRaw: \"float(10,0)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tDouble\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.FloatType{T: \"double\", Precision: 10},\n\t\t\t\t\t\t\tRaw: \"double(10,0)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tReal\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.FloatType{T: \"double\", Precision: 10},\n\t\t\t\t\t\t\tRaw: \"double(10,0)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTimestamp\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp\"},\n\t\t\t\t\t\t\tRaw: \"timestamp\", Null: true},\n\t\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\t\tX: func() string {\n\t\t\t\t\t\t\t\tif t.mariadb() {\n\t\t\t\t\t\t\t\t\treturn \"(current_timestamp())\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn \"CURRENT_TIMESTAMP\"\n\t\t\t\t\t\t\t}(),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTimestampFraction\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp\", Precision: intp(6)},\n\t\t\t\t\t\t\tRaw: \"timestamp(6)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\t\tX: func() string {\n\t\t\t\t\t\t\t\tif t.mariadb() {\n\t\t\t\t\t\t\t\t\treturn \"(current_timestamp(6))\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn \"CURRENT_TIMESTAMP(6)\"\n\t\t\t\t\t\t\t}(),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTimestampOnUpdate\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp\"},\n\t\t\t\t\t\t\tRaw: \"timestamp\", Null: true},\n\t\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\t\tX: func() string {\n\t\t\t\t\t\t\t\tif t.mariadb() {\n\t\t\t\t\t\t\t\t\treturn \"(current_timestamp())\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn \"CURRENT_TIMESTAMP\"\n\t\t\t\t\t\t\t}(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&mysql.OnUpdate{\n\t\t\t\t\t\t\t\tA: func() string {\n\t\t\t\t\t\t\t\t\tif t.mariadb() {\n\t\t\t\t\t\t\t\t\t\treturn \"current_timestamp()\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn \"CURRENT_TIMESTAMP\"\n\t\t\t\t\t\t\t\t}(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTimestampFractionOnUpdate\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp\", Precision: intp(6)}, Raw: \"timestamp(6)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\t\tX: func() string {\n\t\t\t\t\t\t\t\tif t.mariadb() {\n\t\t\t\t\t\t\t\t\treturn \"(current_timestamp(6))\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn \"CURRENT_TIMESTAMP(6)\"\n\t\t\t\t\t\t\t}(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&mysql.OnUpdate{\n\t\t\t\t\t\t\t\tA: func() string {\n\t\t\t\t\t\t\t\t\tif t.mariadb() {\n\t\t\t\t\t\t\t\t\t\treturn \"current_timestamp(6)\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn \"CURRENT_TIMESTAMP(6)\"\n\t\t\t\t\t\t\t\t}(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tDate\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"date\"},\n\t\t\t\t\t\t\tRaw: \"date\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTime\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"time\"},\n\t\t\t\t\t\t\tRaw: \"time\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tDateTime\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"datetime\"},\n\t\t\t\t\t\t\tRaw: \"datetime\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tYear\",\n\t\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\t\tType: &schema.TimeType{\n\t\t\t\t\t\t\t\tT: \"year\",\n\t\t\t\t\t\t\t\tPrecision: func() *int {\n\t\t\t\t\t\t\t\t\t// From MySQL 8.0.19, display width is deprecated in YEAR types.\n\t\t\t\t\t\t\t\t\tif t.version == \"mysql8\" {\n\t\t\t\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tp := 4\n\t\t\t\t\t\t\t\t\treturn &p\n\t\t\t\t\t\t\t\t}(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"year\"}, \"year(4)\"), Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tVarchar\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"varchar\", Size: 10},\n\t\t\t\t\t\t\tRaw: \"varchar(10)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: t.quoted(\"Titan\")},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tChar\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"char\", Size: 25},\n\t\t\t\t\t\t\tRaw: \"char(25)\", Null: false},\n\t\t\t\t\t\tDefault: &schema.Literal{V: t.quoted(\"Olimpia\")},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tVarBinary\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"varbinary\", Size: intp(30)},\n\t\t\t\t\t\t\tRaw: \"varbinary(30)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: t.valueByVersion(map[string]string{\"mysql8\": \"0x546974616E\"}, t.quoted(\"Titan\"))},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tBinary\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"binary\", Size: intp(5)},\n\t\t\t\t\t\t\tRaw: \"binary(5)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: t.valueByVersion(map[string]string{\"mysql8\": \"0x546974616E\"}, t.quoted(\"Titan\"))},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tBlob\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"tinyblob\"},\n\t\t\t\t\t\t\tRaw: \"tinyblob\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTinyBlob\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"tinyblob\"},\n\t\t\t\t\t\t\tRaw: \"tinyblob\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tMediumBlob\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"mediumblob\"},\n\t\t\t\t\t\t\tRaw: \"mediumblob\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tLongBlob\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"longblob\"},\n\t\t\t\t\t\t\tRaw: \"longblob\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tText\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"tinytext\", Size: 0},\n\t\t\t\t\t\t\tRaw: \"tinytext\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTinyText\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"tinytext\", Size: 0},\n\t\t\t\t\t\t\tRaw: \"tinytext\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tMediumText\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"mediumtext\", Size: 0},\n\t\t\t\t\t\t\tRaw: \"mediumtext\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tLongText\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"longtext\", Size: 0},\n\t\t\t\t\t\t\tRaw: \"longtext\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tEnum\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.EnumType{T: \"enum\", Values: []string{\"a\", \"b\"}},\n\t\t\t\t\t\t\tRaw: \"enum('a','b')\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tSet\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &mysql.SetType{Values: []string{\"a\", \"b\"}},\n\t\t\t\t\t\t\tRaw: \"set('a','b')\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tGeometry\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"geometry\"},\n\t\t\t\t\t\t\tRaw: \"geometry\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tPoint\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"point\"},\n\t\t\t\t\t\t\tRaw: \"point\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tMultiPoint\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"multipoint\"},\n\t\t\t\t\t\t\tRaw: \"multipoint\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tLineString\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"linestring\"},\n\t\t\t\t\t\t\tRaw: \"linestring\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tMultiLineString\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"multilinestring\"},\n\t\t\t\t\t\t\tRaw: \"multilinestring\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tPolygon\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"polygon\"},\n\t\t\t\t\t\t\tRaw: \"polygon\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tMultiPolygon\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"multipolygon\"},\n\t\t\t\t\t\t\tRaw: \"multipolygon\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tGeometryCollection\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: t.valueByVersion(\n\t\t\t\t\t\t\tmap[string]string{\"mysql8\": \"geomcollection\"}, \"geometrycollection\")},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"geomcollection\"},\n\t\t\t\t\t\t\t\t\"geometrycollection\"), Null: true},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\trmCreateStmt(ts)\n\t\t\trequire.EqualValues(t, &expected, ts)\n\t\t\tt.hclDriftTest(n, realm, expected)\n\t\t})\n\t})\n\tt.Run(\"JSON\", func(t *testing.T) {\n\t\tddl := `\ncreate table atlas_types_sanity\n(\n    tJSON         json          default                   null\n) CHARSET = latin1 COLLATE latin1_swedish_ci;\n`\n\t\tmyRun(t, func(t *myTest) {\n\t\t\tif t.version == \"mysql56\" {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tt.dropTables(n)\n\t\t\t_, err := t.db.Exec(ddl)\n\t\t\trequire.NoError(t, err)\n\t\t\trealm := t.loadRealm()\n\t\t\trequire.Len(t, realm.Schemas, 1)\n\t\t\tts, ok := realm.Schemas[0].Table(n)\n\t\t\trequire.True(t, ok)\n\t\t\texpected := schema.Table{\n\t\t\t\tName: n,\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t&mysql.Engine{V: \"InnoDB\", Default: true},\n\t\t\t\t},\n\t\t\t\tSchema: realm.Schemas[0],\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\tfunc() *schema.Column {\n\t\t\t\t\t\tc := &schema.Column{Name: \"tJSON\", Type: &schema.ColumnType{Type: &schema.JSONType{T: \"json\"}, Raw: \"json\", Null: true}}\n\t\t\t\t\t\tswitch t.version {\n\t\t\t\t\t\tcase \"maria107\":\n\t\t\t\t\t\t\tc.Attrs = []schema.Attr{}\n\t\t\t\t\t\tcase \"maria102\", \"maria103\":\n\t\t\t\t\t\t\tc.Type.Raw = \"longtext\"\n\t\t\t\t\t\t\tc.Type.Type = &schema.StringType{T: \"longtext\"}\n\t\t\t\t\t\t\tc.Attrs = []schema.Attr{\n\t\t\t\t\t\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t\t\t\t\t&schema.Collation{V: \"utf8mb4_bin\"},\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn c\n\t\t\t\t\t}(),\n\t\t\t\t},\n\t\t\t}\n\t\t\trmCreateStmt(ts)\n\t\t\trequire.EqualValues(t, &expected, ts)\n\t\t})\n\t})\n\n\tt.Run(\"ImplicitIndexes\", func(t *testing.T) {\n\t\tmyRun(t, func(t *myTest) {\n\t\t\ttestImplicitIndexes(t, t.db)\n\t\t})\n\t})\n}\n\nfunc (t *myTest) url(dbname string) string {\n\td := \"mysql\"\n\tpass := \":pass\"\n\tif t.tidb() {\n\t\tpass = \"\"\n\t}\n\tif t.mariadb() {\n\t\td = \"mariadb\"\n\t}\n\treturn fmt.Sprintf(\"%s://root%s@localhost:%d/%s?parseTime=true\", d, pass, t.port, dbname)\n}\n\nfunc (t *myTest) driver() migrate.Driver {\n\treturn t.drv\n}\n\nfunc (t *myTest) revisionsStorage() migrate.RevisionReadWriter {\n\treturn t.rrw\n}\n\nfunc (t *myTest) applyHcl(spec string) {\n\trealm := t.loadRealm()\n\tvar desired schema.Schema\n\terr := mysql.EvalHCLBytes([]byte(spec), &desired, nil)\n\trequire.NoError(t, err)\n\texisting := realm.Schemas[0]\n\trequire.NoError(t, err)\n\tdiff, err := t.drv.SchemaDiff(existing, &desired)\n\trequire.NoError(t, err)\n\terr = t.drv.ApplyChanges(context.Background(), diff)\n\trequire.NoError(t, err)\n}\n\nfunc (t *myTest) applyRealmHcl(spec string) {\n\trealm := t.loadRealm()\n\tvar desired schema.Realm\n\terr := mysql.EvalHCLBytes([]byte(spec), &desired, nil)\n\trequire.NoError(t, err)\n\tdiff, err := t.drv.RealmDiff(realm, &desired)\n\trequire.NoError(t, err)\n\terr = t.drv.ApplyChanges(context.Background(), diff)\n\trequire.NoError(t, err)\n}\n\nfunc (t *myTest) diff(t1, t2 *schema.Table) []schema.Change {\n\tchanges, err := t.drv.TableDiff(t1, t2)\n\trequire.NoError(t, err)\n\treturn changes\n}\n\nfunc (t *myTest) migrate(changes ...schema.Change) {\n\terr := t.drv.ApplyChanges(context.Background(), changes)\n\trequire.NoError(t, err)\n}\n\nfunc (t *myTest) dropTables(names ...string) {\n\tt.Cleanup(func() {\n\t\t_, err := t.db.Exec(\"DROP TABLE IF EXISTS \" + strings.Join(names, \", \"))\n\t\trequire.NoError(t.T, err, \"drop tables %q\", names)\n\t})\n}\n\nfunc (t *myTest) dropSchemas(names ...string) {\n\tt.Cleanup(func() {\n\t\tfor _, n := range names {\n\t\t\t_, err := t.db.Exec(\"DROP DATABASE IF EXISTS \" + n)\n\t\t\trequire.NoError(t.T, err, \"drop db %q\", names)\n\t\t}\n\t})\n}\n\nfunc (t *myTest) realm() *schema.Realm {\n\tr := &schema.Realm{\n\t\tSchemas: []*schema.Schema{\n\t\t\t{\n\t\t\t\tName:  \"test\",\n\t\t\t\tAttrs: t.defaultAttrs(),\n\t\t\t},\n\t\t},\n\t\tAttrs: t.defaultAttrs(),\n\t}\n\tr.Schemas[0].Realm = r\n\treturn r\n}\n\nfunc (t *myTest) users() *schema.Table {\n\tusersT := &schema.Table{\n\t\tName:   \"users\",\n\t\tSchema: t.realm().Schemas[0],\n\t\tColumns: []*schema.Column{\n\t\t\t{\n\t\t\t\tName:  \"id\",\n\t\t\t\tType:  &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t\tAttrs: []schema.Attr{&mysql.AutoIncrement{}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"x\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t},\n\t\t},\n\t\tAttrs: t.defaultAttrs(),\n\t}\n\tusersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}\n\treturn usersT\n}\n\nfunc (t *myTest) posts() *schema.Table {\n\tusersT := t.users()\n\tpostsT := &schema.Table{\n\t\tName:   \"posts\",\n\t\tSchema: t.realm().Schemas[0],\n\t\tColumns: []*schema.Column{\n\t\t\t{\n\t\t\t\tName:  \"id\",\n\t\t\t\tType:  &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t\tAttrs: []schema.Attr{&mysql.AutoIncrement{}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"author_id\",\n\t\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\t\tDefault: &schema.RawExpr{X: \"10\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"ctime\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"timestamp\", Type: &schema.TimeType{T: \"timestamp\"}},\n\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\tX: \"CURRENT_TIMESTAMP\",\n\t\t\t\t},\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&mysql.OnUpdate{\n\t\t\t\t\t\tA: \"CURRENT_TIMESTAMP\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tAttrs: t.defaultAttrs(),\n\t}\n\tpostsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}\n\tpostsT.Indexes = []*schema.Index{\n\t\t{Name: \"author_id\", Parts: []*schema.IndexPart{{C: postsT.Columns[1]}}},\n\t\t{Name: \"id_author_id_unique\", Unique: true, Parts: []*schema.IndexPart{{C: postsT.Columns[1]}, {C: postsT.Columns[0]}}},\n\t}\n\tpostsT.ForeignKeys = []*schema.ForeignKey{\n\t\t{Symbol: \"author_id\", Table: postsT, Columns: postsT.Columns[1:2], RefTable: usersT, RefColumns: usersT.Columns[:1], OnDelete: schema.NoAction},\n\t}\n\treturn postsT\n}\n\nfunc (t *myTest) valueByVersion(values map[string]string, defaults string) string {\n\tif v, ok := values[t.version]; ok {\n\t\treturn v\n\t}\n\treturn defaults\n}\n\nfunc (t *myTest) intByVersion(values map[string]int, defaults int) int {\n\tif v, ok := values[t.version]; ok {\n\t\treturn v\n\t}\n\treturn defaults\n}\n\nfunc (t *myTest) quoted(s string) string {\n\tc := \"\\\"\"\n\tif t.mariadb() {\n\t\tc = \"'\"\n\t}\n\treturn c + s + c\n}\n\nfunc (t *myTest) loadRealm() *schema.Realm {\n\tr, err := t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\tSchemas: []string{\"test\"},\n\t\tMode:    schema.InspectSchemas | schema.InspectTables,\n\t})\n\trequire.NoError(t, err)\n\treturn r\n}\n\nfunc (t *myTest) loadUsers() *schema.Table {\n\treturn t.loadTable(\"users\")\n}\n\nfunc (t *myTest) loadPosts() *schema.Table {\n\treturn t.loadTable(\"posts\")\n}\n\nfunc (t *myTest) loadTable(name string) *schema.Table {\n\trealm := t.loadRealm()\n\trequire.Len(t, realm.Schemas, 1)\n\ttable, ok := realm.Schemas[0].Table(name)\n\trequire.True(t, ok)\n\treturn table\n}\n\nfunc (t *myTest) mariadb() bool { return strings.HasPrefix(t.version, \"maria\") }\nfunc (t *myTest) tidb() bool    { return strings.HasPrefix(t.version, \"tidb\") }\n\n// defaultConfig returns the default charset and\n// collation configuration based on the MySQL version.\nfunc (t *myTest) defaultAttrs() []schema.Attr {\n\tvar (\n\t\tcharset   = \"latin1\"\n\t\tcollation = \"latin1_swedish_ci\"\n\t)\n\tswitch {\n\tcase strings.Contains(t.version, \"tidb\"):\n\t\tcharset = \"utf8mb4\"\n\t\tcollation = \"utf8mb4_bin\"\n\tcase t.version == \"mysql8\":\n\t\tcharset = \"utf8mb4\"\n\t\tcollation = \"utf8mb4_0900_ai_ci\"\n\tcase t.version == \"maria107\":\n\t\tcharset = \"utf8mb4\"\n\t\tcollation = \"utf8mb4_general_ci\"\n\t}\n\treturn []schema.Attr{\n\t\t&schema.Charset{\n\t\t\tV: charset,\n\t\t},\n\t\t&schema.Collation{\n\t\t\tV: collation,\n\t\t},\n\t}\n}\n\nfunc (t *myTest) hclDriftTest(n string, realm *schema.Realm, expected schema.Table) {\n\tspec, err := mysql.MarshalHCL(realm.Schemas[0])\n\trequire.NoError(t, err)\n\tt.dropTables(n)\n\tt.applyHcl(string(spec))\n\trealm = t.loadRealm()\n\trequire.Len(t, realm.Schemas, 1)\n\tts, ok := realm.Schemas[0].Table(n)\n\trequire.True(t, ok)\n\trmCreateStmt(ts)\n\trequire.EqualValues(t, &expected, ts)\n}\n\nfunc rmCreateStmt(t *schema.Table) {\n\tfor i := range t.Attrs {\n\t\tif _, ok := t.Attrs[i].(*mysql.CreateStmt); ok {\n\t\t\tt.Attrs = append(t.Attrs[:i], t.Attrs[i+1:]...)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc intp(i int) *int { return &i }\n"
  },
  {
    "path": "internal/integration/postgres_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage integration\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/postgres\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t_ \"github.com/lib/pq\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype pgTest struct {\n\t*testing.T\n\tdb      *sql.DB\n\tdrv     migrate.Driver\n\trrw     migrate.RevisionReadWriter\n\tversion string\n\tport    int\n\tonce    sync.Once\n}\n\nvar pgTests = map[string]*pgTest{\n\t\"postgres-ext-postgis\": {port: 5429},\n\t\"postgres10\":           {port: 5430},\n\t\"postgres11\":           {port: 5431},\n\t\"postgres12\":           {port: 5432},\n\t\"postgres13\":           {port: 5433},\n\t\"postgres14\":           {port: 5434},\n\t\"postgres15\":           {port: 5435},\n}\n\nfunc pgRun(t *testing.T, fn func(*pgTest)) {\n\tfor version, tt := range pgTests {\n\t\tif flagVersion == \"\" || flagVersion == version {\n\t\t\tt.Run(version, func(t *testing.T) {\n\t\t\t\ttt.once.Do(func() {\n\t\t\t\t\tvar err error\n\t\t\t\t\ttt.version = version\n\t\t\t\t\ttt.rrw = &rrw{}\n\t\t\t\t\ttt.db, err = sql.Open(\"postgres\", fmt.Sprintf(\"host=localhost port=%d user=postgres dbname=test password=pass sslmode=disable\", tt.port))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Fatalln(err)\n\t\t\t\t\t}\n\t\t\t\t\tdbs = append(dbs, tt.db) // close connection after all tests have been run\n\t\t\t\t\t// the postgis/postgis image enables the postgis_topology and postgis_tiger_geocoder extensions,\n\t\t\t\t\t// this creates a few unwanted schemas, so we drop it.\n\t\t\t\t\t// https://github.com/postgis/docker-postgis/issues/187\n\t\t\t\t\tif tt.version == \"postgres-ext-postgis\" {\n\t\t\t\t\t\tschemasToDrop := []string{\n\t\t\t\t\t\t\t\"tiger\",      // created by postgis_tiger_geocoder\n\t\t\t\t\t\t\t\"tiger_data\", // created by postgis_tiger_geocoder\n\t\t\t\t\t\t\t\"topology\",   // created by postgis_topology\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor _, s := range schemasToDrop {\n\t\t\t\t\t\t\tif _, err := tt.db.Exec(\"DROP SCHEMA IF EXISTS \" + s + \" CASCADE;\"); err != nil {\n\t\t\t\t\t\t\t\tlog.Fatalf(\"error dropping schema %q: %v\", s, err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttt.drv, err = postgres.Open(tt.db)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Fatalln(err)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\ttt := &pgTest{T: t, db: tt.db, drv: tt.drv, version: version, port: tt.port, rrw: tt.rrw}\n\t\t\t\tfn(tt)\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc TestPostgres_Executor(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\ttestExecutor(t)\n\t})\n}\n\nfunc TestPostgres_AddDropTable(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\ttestAddDrop(t)\n\t})\n}\n\nfunc TestPostgres_Relation(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\ttestRelation(t)\n\t})\n}\n\nfunc TestPostgres_NoSchema(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\tt.Cleanup(func() {\n\t\t\t_, err := t.db.Exec(\"CREATE SCHEMA IF NOT EXISTS public\")\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t\t_, err := t.db.Exec(\"DROP SCHEMA IF EXISTS public CASCADE\")\n\t\trequire.NoError(t, err)\n\t\tr, err := t.drv.InspectRealm(context.Background(), nil)\n\t\trequire.NoError(t, err)\n\t\trequire.Nil(t, r.Schemas)\n\t})\n}\n\nfunc TestPostgres_AddIndexedColumns(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\tusersT := &schema.Table{\n\t\t\tName:    \"users\",\n\t\t\tColumns: []*schema.Column{{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}}},\n\t\t}\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tt.dropTables(usersT.Name)\n\t\tusersT.Columns = append(usersT.Columns, &schema.Column{\n\t\t\tName:    \"a\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t}, &schema.Column{\n\t\t\tName:    \"b\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t}, &schema.Column{\n\t\t\tName:    \"c\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t})\n\t\tparts := usersT.Columns[len(usersT.Columns)-3:]\n\t\tusersT.Indexes = append(usersT.Indexes, &schema.Index{\n\t\t\tUnique: true,\n\t\t\tName:   \"a_b_c_unique\",\n\t\t\tParts:  []*schema.IndexPart{{C: parts[0]}, {C: parts[1]}, {C: parts[2]}},\n\t\t})\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.NotEmpty(t, changes, \"usersT contains 3 new columns and 1 new index\")\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\n\t\t// Dropping a column involves in a multi-column\n\t\t// index causes the index to be dropped as well.\n\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, t.loadUsers())\n\t\tusersT = t.loadUsers()\n\t\t_, ok := usersT.Index(\"a_b_c_unique\")\n\t\trequire.False(t, ok)\n\t})\n}\n\nfunc TestPostgres_ColumnCheck(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\tusersT := &schema.Table{\n\t\t\tName:  \"users\",\n\t\t\tAttrs: []schema.Attr{schema.NewCheck().SetName(\"users_c_check\").SetExpr(\"c > 5\")},\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t{Name: \"c\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t},\n\t\t}\n\t\tt.dropTables(usersT.Name)\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestPostgres_AddColumns(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\tusersT := t.users()\n\t\tt.dropTables(usersT.Name)\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t_, err := t.db.Exec(\"CREATE EXTENSION IF NOT EXISTS hstore\")\n\t\trequire.NoError(t, err)\n\t\tusersT.Columns = append(\n\t\t\tusersT.Columns,\n\t\t\t&schema.Column{Name: \"a\", Type: &schema.ColumnType{Type: &schema.BinaryType{T: \"bytea\"}}},\n\t\t\t&schema.Column{Name: \"b\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"double precision\", Precision: 10}}, Default: &schema.Literal{V: \"10.1\"}},\n\t\t\t&schema.Column{Name: \"c\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"character\"}}, Default: &schema.Literal{V: \"'y'\"}},\n\t\t\t&schema.Column{Name: \"d\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 10, Scale: 2}}, Default: &schema.Literal{V: \"0.99\"}},\n\t\t\t&schema.Column{Name: \"e\", Type: &schema.ColumnType{Type: &schema.JSONType{T: \"json\"}}, Default: &schema.Literal{V: \"'{}'\"}},\n\t\t\t&schema.Column{Name: \"f\", Type: &schema.ColumnType{Type: &schema.JSONType{T: \"jsonb\"}}, Default: &schema.Literal{V: \"'1'\"}},\n\t\t\t&schema.Column{Name: \"g\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"float\", Precision: 10}}, Default: &schema.Literal{V: \"'1'\"}},\n\t\t\t&schema.Column{Name: \"h\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"float\", Precision: 30}}, Default: &schema.Literal{V: \"'1'\"}},\n\t\t\t&schema.Column{Name: \"i\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"float\", Precision: 53}}, Default: &schema.Literal{V: \"1\"}},\n\t\t\t&schema.Column{Name: \"j\", Type: &schema.ColumnType{Type: &postgres.SerialType{T: \"serial\"}}},\n\t\t\t&schema.Column{Name: \"k\", Type: &schema.ColumnType{Type: &postgres.CurrencyType{T: \"money\"}}, Default: &schema.Literal{V: \"'100'\"}},\n\t\t\t&schema.Column{Name: \"l\", Type: &schema.ColumnType{Type: &postgres.CurrencyType{T: \"money\"}, Null: true}, Default: &schema.RawExpr{X: \"'52093.89'::money\"}},\n\t\t\t&schema.Column{Name: \"m\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}, Null: true}, Default: &schema.Literal{V: \"false\"}},\n\t\t\t&schema.Column{Name: \"n\", Type: &schema.ColumnType{Type: &schema.SpatialType{T: \"point\"}, Null: true}, Default: &schema.Literal{V: \"'(1,2)'\"}},\n\t\t\t&schema.Column{Name: \"o\", Type: &schema.ColumnType{Type: &schema.SpatialType{T: \"line\"}, Null: true}, Default: &schema.Literal{V: \"'{1,2,3}'\"}},\n\t\t\t&schema.Column{Name: \"p\", Type: &schema.ColumnType{Type: &postgres.UserDefinedType{T: \"hstore\"}, Null: true}, Default: &schema.RawExpr{X: \"'a => 1'\"}},\n\t\t\t&schema.Column{Name: \"q\", Type: &schema.ColumnType{Type: &postgres.ArrayType{Type: &schema.StringType{T: \"text\"}, T: \"text[]\"}, Null: true}, Default: &schema.Literal{V: \"'{}'\"}},\n\t\t)\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 17)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestPostgres_ColumnInt(t *testing.T) {\n\tctx := context.Background()\n\trun := func(t *testing.T, change func(*schema.Column)) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}}},\n\t\t\t}\n\t\t\terr := t.drv.ApplyChanges(ctx, []schema.Change{&schema.AddTable{T: usersT}})\n\t\t\trequire.NoError(t, err)\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tchange(usersT.Columns[0])\n\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 1)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t}\n\n\tt.Run(\"ChangeNull\", func(t *testing.T) {\n\t\trun(t, func(c *schema.Column) {\n\t\t\tc.Type.Null = true\n\t\t})\n\t})\n\n\tt.Run(\"ChangeType\", func(t *testing.T) {\n\t\trun(t, func(c *schema.Column) {\n\t\t\tc.Type.Type.(*schema.IntegerType).T = \"integer\"\n\t\t})\n\t})\n\n\tt.Run(\"ChangeDefault\", func(t *testing.T) {\n\t\trun(t, func(c *schema.Column) {\n\t\t\tc.Default = &schema.RawExpr{X: \"0\"}\n\t\t})\n\t})\n}\n\nfunc TestPostgres_ColumnArray(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\tusersT := t.users()\n\t\tt.dropTables(usersT.Name)\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\n\t\t// Add column.\n\t\tusersT.Columns = append(\n\t\t\tusersT.Columns,\n\t\t\t&schema.Column{Name: \"a\", Type: &schema.ColumnType{Raw: \"int[]\", Type: &postgres.ArrayType{Type: &schema.IntegerType{T: \"int\"}, T: \"int[]\"}}, Default: &schema.Literal{V: \"'{1}'\"}},\n\t\t)\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 1)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\n\t\t// Check default.\n\t\tusersT.Columns[2].Default = &schema.RawExpr{X: \"ARRAY[1]\"}\n\t\tensureNoChange(t, usersT)\n\n\t\t// Change default.\n\t\tusersT.Columns[2].Default = &schema.RawExpr{X: \"ARRAY[1,2]\"}\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 1)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestPostgres_Enums(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\tctx := context.Background()\n\t\tusersT := &schema.Table{\n\t\t\tName:   \"users\",\n\t\t\tSchema: t.realm().Schemas[0],\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"state\", Type: &schema.ColumnType{Type: &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\"}}}},\n\t\t\t},\n\t\t}\n\t\tt.Cleanup(func() {\n\t\t\t_, err := t.drv.ExecContext(ctx, \"DROP TYPE IF EXISTS state, day\")\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\t// Create table with an enum column.\n\t\terr := t.drv.ApplyChanges(ctx, []schema.Change{\n\t\t\t&schema.AddObject{O: &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\"}, Schema: usersT.Schema}},\n\t\t\t&schema.AddTable{T: usersT},\n\t\t})\n\t\trequire.NoError(t, err, \"create a new table with an enum column\")\n\t\tt.dropTables(usersT.Name)\n\t\tensureNoChange(t, usersT)\n\n\t\t// Add another enum column.\n\t\tusersT.Columns = append(\n\t\t\tusersT.Columns,\n\t\t\t&schema.Column{Name: \"day\", Type: &schema.ColumnType{Type: &schema.EnumType{T: \"day\", Values: []string{\"sunday\", \"monday\"}}}},\n\t\t)\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 1)\n\t\terr = t.drv.ApplyChanges(ctx, []schema.Change{\n\t\t\t&schema.AddObject{O: &schema.EnumType{T: \"day\", Values: []string{\"sunday\", \"monday\"}, Schema: usersT.Schema}},\n\t\t\t&schema.ModifyTable{T: usersT, Changes: changes},\n\t\t})\n\t\trequire.NoError(t, err, \"add a new enum column to existing table\")\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestPostgres_ForeignKey(t *testing.T) {\n\tt.Run(\"ChangeAction\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\tusersT, postsT := t.users(), t.posts()\n\t\t\tt.dropTables(postsT.Name, usersT.Name)\n\t\t\tt.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})\n\t\t\tensureNoChange(t, postsT, usersT)\n\n\t\t\tpostsT = t.loadPosts()\n\t\t\tfk, ok := postsT.ForeignKey(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tfk.OnUpdate = schema.SetNull\n\t\t\tfk.OnDelete = schema.Cascade\n\t\t\tchanges := t.diff(t.loadPosts(), postsT)\n\t\t\trequire.Len(t, changes, 1)\n\t\t\tmodifyF, ok := changes[0].(*schema.ModifyForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)\n\n\t\t\tt.migrate(&schema.ModifyTable{T: postsT, Changes: changes})\n\t\t\tensureNoChange(t, postsT, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"UnsetNull\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\tusersT, postsT := t.users(), t.posts()\n\t\t\tt.dropTables(postsT.Name, usersT.Name)\n\t\t\tfk, ok := postsT.ForeignKey(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tfk.OnDelete = schema.SetNull\n\t\t\tfk.OnUpdate = schema.SetNull\n\t\t\tt.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})\n\t\t\tensureNoChange(t, postsT, usersT)\n\n\t\t\tpostsT = t.loadPosts()\n\t\t\tc, ok := postsT.Column(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tc.Type.Null = false\n\t\t\tfk, ok = postsT.ForeignKey(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tfk.OnUpdate = schema.NoAction\n\t\t\tfk.OnDelete = schema.NoAction\n\t\t\tchanges := t.diff(t.loadPosts(), postsT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\tmodifyC, ok := changes[0].(*schema.ModifyColumn)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyC.Change == schema.ChangeNull)\n\t\t\tmodifyF, ok := changes[1].(*schema.ModifyForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)\n\n\t\t\tt.migrate(&schema.ModifyTable{T: postsT, Changes: changes})\n\t\t\tensureNoChange(t, postsT, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"AddDrop\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\tusersT := t.users()\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tensureNoChange(t, usersT)\n\n\t\t\t// Add foreign key.\n\t\t\tusersT.Columns = append(usersT.Columns, &schema.Column{\n\t\t\t\tName: \"spouse_id\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\t})\n\t\t\tusersT.ForeignKeys = append(usersT.ForeignKeys, &schema.ForeignKey{\n\t\t\t\tSymbol:     \"spouse_id\",\n\t\t\t\tTable:      usersT,\n\t\t\t\tColumns:    usersT.Columns[len(usersT.Columns)-1:],\n\t\t\t\tRefTable:   usersT,\n\t\t\t\tRefColumns: usersT.Columns[:1],\n\t\t\t\tOnDelete:   schema.NoAction,\n\t\t\t})\n\n\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\taddC, ok := changes[0].(*schema.AddColumn)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, \"spouse_id\", addC.C.Name)\n\t\t\taddF, ok := changes[1].(*schema.AddForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, \"spouse_id\", addF.F.Symbol)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\n\t\t\t// Drop foreign keys.\n\t\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\t\tusersT.ForeignKeys = usersT.ForeignKeys[:len(usersT.ForeignKeys)-1]\n\t\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n}\n\nfunc TestPostgres_EntGlobalUniqueID(t *testing.T) {\n\t// Migration to global unique identifiers.\n\tpgRun(t, func(t *pgTest) {\n\t\tctx := context.Background()\n\t\tt.dropTables(\"global_id\")\n\t\t_, err := t.driver().ExecContext(ctx, \"CREATE TABLE global_id (id int NOT NULL GENERATED BY DEFAULT AS IDENTITY, PRIMARY KEY(id))\")\n\t\trequire.NoError(t, err)\n\t\t_, err = t.driver().ExecContext(ctx, \"ALTER TABLE global_id ALTER COLUMN id RESTART WITH 1024\")\n\t\trequire.NoError(t, err)\n\t\t_, err = t.driver().ExecContext(ctx, \"INSERT INTO global_id VALUES (default), (default)\")\n\t\trequire.NoError(t, err)\n\t\tvar id int\n\t\trequire.NoError(t, t.db.QueryRow(\"SELECT id FROM global_id\").Scan(&id))\n\t\trequire.Equal(t, 1024, id)\n\t\t_, err = t.driver().ExecContext(ctx, \"DELETE FROM global_id WHERE id = 1024\")\n\t\trequire.NoError(t, err)\n\n\t\tglobalT := t.loadTable(\"global_id\")\n\t\tc, ok := globalT.Column(\"id\")\n\t\trequire.True(t, ok)\n\t\trequire.EqualValues(t, 1, c.Attrs[0].(*postgres.Identity).Sequence.Start)\n\t\tt.migrate(&schema.ModifyTable{\n\t\t\tT: globalT,\n\t\t\tChanges: []schema.Change{\n\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\tFrom: globalT.Columns[0],\n\t\t\t\t\tTo: schema.NewIntColumn(\"id\", \"int\").\n\t\t\t\t\t\tAddAttrs(&postgres.Identity{\n\t\t\t\t\t\t\tGeneration: \"BY DEFAULT\",\n\t\t\t\t\t\t\tSequence: &postgres.Sequence{\n\t\t\t\t\t\t\t\tStart: 1024,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\tChange: schema.ChangeAttr,\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\t_, err = t.driver().ExecContext(ctx, \"INSERT INTO global_id VALUES (default), (default)\")\n\t\trequire.NoError(t, err)\n\t\tglobalT = t.loadTable(\"global_id\")\n\t\tc, ok = globalT.Column(\"id\")\n\t\trequire.True(t, ok)\n\t\trequire.EqualValues(t, 1024, c.Attrs[0].(*postgres.Identity).Sequence.Start)\n\t})\n}\n\nfunc TestPostgres_AdvisoryLock(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\ttestAdvisoryLock(t.T, t.drv.(schema.Locker))\n\t})\n}\n\nfunc TestPostgres_HCL(t *testing.T) {\n\tfull := `\nschema \"public\" {\n}\ntable \"users\" {\n\tschema = schema.public\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tprimary_key {\n\t\tcolumns = [table.users.column.id]\n\t}\n}\ntable \"posts\" {\n\tschema = schema.public\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tcolumn \"tags\" {\n\t\ttype = sql(\"text[]\")\n\t}\n\tcolumn \"author_id\" {\n\t\ttype = int\n\t}\n\tforeign_key \"author\" {\n\t\tcolumns = [\n\t\t\ttable.posts.column.author_id,\n\t\t]\n\t\tref_columns = [\n\t\t\ttable.users.column.id,\n\t\t]\n\t}\n\tprimary_key {\n\t\tcolumns = [table.users.column.id]\n\t}\n}\n`\n\tempty := `\nschema \"public\" {\n}\n`\n\tpgRun(t, func(t *pgTest) {\n\t\ttestHCLIntegration(t, full, empty)\n\t})\n}\n\nfunc TestPostgres_HCL_Realm(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\tt.dropSchemas(\"second\")\n\t\trealm := t.loadRealm()\n\t\thcl, err := postgres.MarshalHCL(realm)\n\t\trequire.NoError(t, err)\n\t\twa := string(hcl) + `\nschema \"second\" {\n  comment = \"second schema\"\n}\n`\n\t\tt.applyRealmHcl(wa)\n\t\trealm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{})\n\t\trequire.NoError(t, err)\n\t\t_, ok := realm.Schema(\"public\")\n\t\trequire.True(t, ok)\n\t\ts2, ok := realm.Schema(\"second\")\n\t\trequire.True(t, ok)\n\t\trequire.Len(t, s2.Attrs, 1)\n\t\trequire.Equal(t, \"second schema\", s2.Attrs[0].(*schema.Comment).Text)\n\t})\n}\n\nfunc TestPostgres_HCL_ForeignKeyCrossSchema(t *testing.T) {\n\tconst expected = `table \"credit_cards\" {\n  schema = schema.financial\n  column \"id\" {\n    null = false\n    type = serial\n  }\n  column \"user_id\" {\n    null = false\n    type = integer\n  }\n  primary_key {\n    columns = [column.id]\n  }\n  foreign_key \"user_id_fkey\" {\n    columns     = [column.user_id]\n    ref_columns = [table.users.users.column.id]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n}\ntable \"financial\" \"t\" {\n  schema = schema.financial\n  column \"t_id\" {\n    null = false\n    type = uuid\n  }\n  primary_key {\n    columns = [column.t_id]\n  }\n  foreign_key \"fk_t_id\" {\n    columns     = [column.t_id]\n    ref_columns = [table.users.t.column.id]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n}\ntable \"financial\" \"users\" {\n  schema = schema.financial\n  column \"id\" {\n    null = false\n    type = serial\n  }\n}\ntable \"users\" \"t\" {\n  schema = schema.users\n  column \"id\" {\n    null = false\n    type = uuid\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\ntable \"users\" \"users\" {\n  schema = schema.users\n  column \"id\" {\n    null = false\n    type = bigserial\n  }\n  column \"email\" {\n    null = false\n    type = character_varying\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\nschema \"financial\" {\n}\nschema \"users\" {\n}\n`\n\tpgRun(t, func(t *pgTest) {\n\t\tt.dropSchemas(\"financial\", \"users\")\n\t\trealm := t.loadRealm()\n\t\thcl, err := postgres.MarshalHCL(realm)\n\t\trequire.NoError(t, err)\n\t\tt.applyRealmHcl(string(hcl) + \"\\n\" + expected)\n\t\trealm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{Schemas: []string{\"users\", \"financial\"}})\n\t\trequire.NoError(t, err)\n\t\tactual, err := postgres.MarshalHCL(realm)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expected, string(actual))\n\t})\n}\n\nfunc (t *pgTest) applyRealmHcl(spec string) {\n\trealm := t.loadRealm()\n\tvar desired schema.Realm\n\terr := postgres.EvalHCLBytes([]byte(spec), &desired, nil)\n\trequire.NoError(t, err)\n\tdiff, err := t.drv.RealmDiff(realm, &desired)\n\trequire.NoError(t, err)\n\terr = t.drv.ApplyChanges(context.Background(), diff)\n\trequire.NoError(t, err)\n}\n\nfunc TestPostgres_Snapshot(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\tclient, err := sqlclient.Open(context.Background(), fmt.Sprintf(\"postgres://postgres:pass@localhost:%d/test?sslmode=disable&search_path=another\", t.port))\n\t\trequire.NoError(t, err)\n\n\t\t_, err = client.ExecContext(context.Background(), \"CREATE SCHEMA another\")\n\t\trequire.NoError(t, err)\n\t\tt.Cleanup(func() {\n\t\t\t_, err = client.ExecContext(context.Background(), \"DROP SCHEMA IF EXISTS another\")\n\t\t\trequire.NoError(t, client.Close())\n\t\t})\n\t\tdrv := client.Driver\n\n\t\t_, err = t.driver().Snapshot(context.Background())\n\t\trequire.ErrorAs(t, err, new(*migrate.NotCleanError))\n\n\t\tr, err := drv.InspectRealm(context.Background(), nil)\n\t\trequire.NoError(t, err)\n\t\trestore, err := drv.Snapshot(context.Background())\n\t\trequire.NoError(t, err) // connected to test schema\n\t\trequire.NoError(t, drv.ApplyChanges(context.Background(), []schema.Change{\n\t\t\t&schema.AddTable{T: schema.NewTable(\"my_table\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"col_1\", \"integer\").SetNull(true),\n\t\t\t\t\tschema.NewIntColumn(\"col_2\", \"bigint\"),\n\t\t\t\t),\n\t\t\t},\n\t\t}))\n\t\tt.Cleanup(func() {\n\t\t\tt.dropTables(\"my_table\")\n\t\t})\n\t\trequire.NoError(t, restore(context.Background()))\n\t\tr1, err := drv.InspectRealm(context.Background(), nil)\n\t\trequire.NoError(t, err)\n\t\tdiff, err := drv.RealmDiff(r1, r)\n\t\trequire.NoError(t, err)\n\t\trequire.Zero(t, diff)\n\t})\n}\n\nfunc TestPostgres_CLI_MigrateApplyBC(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\ttestCLIMigrateApplyBC(t, \"postgres\")\n\t})\n}\n\nfunc TestPostgres_CLI(t *testing.T) {\n\th := `\n\t\t\tschema \"public\" {\n\t\t\t}\n\t\t\ttable \"users\" {\n\t\t\t\tschema = schema.public\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = integer\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [table.users.column.id]\n\t\t\t\t}\n\t\t\t}`\n\tt.Run(\"SchemaInspect\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\ttestCLISchemaInspect(t, h, t.url(\"\"), postgres.EvalHCL)\n\t\t})\n\t})\n\tt.Run(\"SchemaApply\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\ttestCLISchemaApply(t, h, t.url(\"\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyDryRun\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\ttestCLISchemaApplyDry(t, h, t.url(\"\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyWithVars\", func(t *testing.T) {\n\t\th := `\nvariable \"tenant\" {\n\ttype = string\n}\nschema \"tenant\" {\n\tname = var.tenant\n}\ntable \"users\" {\n\tschema = schema.tenant\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n}\n`\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\ttestCLISchemaApply(t, h, t.url(\"\"), \"--var\", \"tenant=public\")\n\t\t})\n\t})\n\tt.Run(\"SchemaDiffRun\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\ttestCLISchemaDiff(t, t.url(\"\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyAutoApprove\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\ttestCLISchemaApplyAutoApprove(t, h, t.url(\"\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyFromMigrationDir\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\ttestCLISchemaApplyFromMigrationDir(t)\n\t\t})\n\t})\n}\n\nfunc TestPostgres_MigrateApply(t *testing.T) {\n\tvar (\n\t\tbin = cliPath(t)\n\t\tctx = context.Background()\n\t)\n\tpgRun(t, func(t *pgTest) {\n\t\t_, err := t.db.ExecContext(ctx, \"DROP DATABASE IF EXISTS migrate_apply\")\n\t\trequire.NoError(t, err)\n\t\t_, err = t.db.ExecContext(ctx, \"CREATE DATABASE migrate_apply\")\n\t\trequire.NoError(t, err)\n\t\tp := t.TempDir()\n\t\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"1.sql\"), []byte(`\nCREATE SCHEMA IF NOT EXISTS public;\nCREATE TABLE public.users (id int);\n`), 0644))\n\t\trequire.NoError(t, exec.Command(bin, \"migrate\", \"hash\", \"--dir\", \"file://\"+p).Run())\n\t\tout, err := exec.Command(\n\t\t\tbin, \"migrate\", \"apply\",\n\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"public\"),\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\t\trequire.Regexp(t, `Migrating to version 1 \\(1 migrations in total\\):\n\n  -- migrating version 1\n    -> CREATE SCHEMA IF NOT EXISTS public;\n    -> CREATE TABLE public.users \\(id int\\);\n  -- ok \\(.+\\)\n\n  -------------------------\n  -- .+\n  -- 1 migration\n  -- 2 sql statements\n`, string(out))\n\n\t\tout, err = exec.Command(\n\t\t\tbin, \"migrate\", \"apply\",\n\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"public\"),\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"No migration files to execute\\n\", string(out))\n\n\t\tout, err = exec.Command(\n\t\t\tbin, \"schema\", \"inspect\",\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"public\"),\n\t\t\t\"--format\", \"{{ range $s := .Realm.Schemas }}{{ range .Tables }}{{ $s.Name }}-{{ .Name }},{{ end }}{{ end }}\",\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"public-atlas_schema_revisions,public-users,\", string(out), \"tables reside on the same public schema\")\n\n\t\t// Database-scope migration, default to atlas_schema_revisions.\n\t\t_, err = exec.Command(\n\t\t\tbin, \"schema\", \"clean\",\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"\"),\n\t\t\t\"--auto-approve\",\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\n\t\tout, err = exec.Command(\n\t\t\tbin, \"migrate\", \"apply\",\n\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"\"),\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\t\trequire.Regexp(t, `Migrating to version 1 \\(1 migrations in total\\):\n\n  -- migrating version 1\n    -> CREATE SCHEMA IF NOT EXISTS public;\n    -> CREATE TABLE public.users \\(id int\\);\n  -- ok \\(.+\\)\n\n  -------------------------\n  -- .+\n  -- 1 migration\n  -- 2 sql statements\n`, string(out))\n\t\tout, err = exec.Command(\n\t\t\tbin, \"migrate\", \"apply\",\n\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"\"),\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"No migration files to execute\\n\", string(out))\n\n\t\tout, err = exec.Command(\n\t\t\tbin, \"schema\", \"inspect\",\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"\"),\n\t\t\t\"--format\", \"{{ range $s := .Realm.Schemas }}{{ range .Tables }}{{ $s.Name }}-{{ .Name }},{{ end }}{{ end }}\",\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"atlas_schema_revisions-atlas_schema_revisions,public-users,\", string(out), \"revisions table should reside in atlas_schema_revisions\")\n\n\t\t// Custom schema-revisions schema.\n\t\t_, err = exec.Command(\n\t\t\tbin, \"schema\", \"clean\",\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"\"),\n\t\t\t\"--auto-approve\",\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\n\t\tout, err = exec.Command(\n\t\t\tbin, \"migrate\", \"apply\",\n\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"\"),\n\t\t\t\"--revisions-schema\", \"mashraki\",\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\t\trequire.Regexp(t, `Migrating to version 1 \\(1 migrations in total\\):\n\n  -- migrating version 1\n    -> CREATE SCHEMA IF NOT EXISTS public;\n    -> CREATE TABLE public.users \\(id int\\);\n  -- ok \\(.+\\)\n\n  -------------------------\n  -- .+\n  -- 1 migration\n  -- 2 sql statements\n`, string(out))\n\t\tout, err = exec.Command(\n\t\t\tbin, \"migrate\", \"apply\",\n\t\t\t\"--dir\", \"file://\"+p,\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"\"),\n\t\t\t\"--revisions-schema\", \"mashraki\",\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"No migration files to execute\\n\", string(out))\n\n\t\tout, err = exec.Command(\n\t\t\tbin, \"schema\", \"inspect\",\n\t\t\t\"--url\", t.dbURL(\"migrate_apply\", \"\"),\n\t\t\t\"--format\", \"{{ range $s := .Realm.Schemas }}{{ range .Tables }}{{ $s.Name }}-{{ .Name }},{{ end }}{{ end }}\",\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"mashraki-atlas_schema_revisions,public-users,\", string(out), \"revisions table should reside in atlas_schema_revisions\")\n\t})\n}\n\nfunc TestPostgres_CLI_MultiSchema(t *testing.T) {\n\th := `\n\t\t\tschema \"public\" {\n\t\t\t}\n\t\t\ttable \"users\" {\n\t\t\t\tschema = schema.public\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = integer\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [column.id]\n\t\t\t\t}\n\t\t\t}\n\t\t\tschema \"test2\" {\n\t\t\t}\n\t\t\ttable \"pets\" {\n\t\t\t\tschema = schema.test2\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = integer\n\t\t\t\t}\n\t\t\t\tcolumn \"owner_id\" {\n\t\t\t\t\ttype = integer\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [column.id]\n\t\t\t\t}\n\t\t\t\tforeign_key \"owner_id\" {\n\t\t\t\t\tcolumns     = [column.owner_id]\n\t\t\t\t\tref_columns = [table.users.column.id]\n\t\t\t\t\ton_delete   = NO_ACTION\n\t\t\t\t\ton_update   = NO_ACTION\n\t\t\t\t}\n\t\t\t}`\n\tt.Run(\"SchemaInspect\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\tt.dropTables(\"users\")\n\t\t\tt.dropSchemas(\"test2\")\n\t\t\ttestCLIMultiSchemaInspect(t, h, t.url(\"\"), []string{\"public\", \"test2\"}, postgres.EvalHCL)\n\t\t})\n\t})\n\tt.Run(\"SchemaApply\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\tt.dropTables(\"users\")\n\t\t\tt.dropSchemas(\"test2\")\n\t\t\ttestCLIMultiSchemaApply(t, h, t.url(\"\"), []string{\"public\", \"test2\"}, postgres.EvalHCL)\n\t\t})\n\t})\n}\n\nfunc TestPostgres_NormalizeRealm(t *testing.T) {\n\tbin := cliPath(t)\n\tpgRun(t, func(t *pgTest) {\n\t\tdir := t.TempDir()\n\t\t_, err := t.db.Exec(\"CREATE DATABASE normalized_realm\")\n\t\trequire.NoError(t, err)\n\t\tdefer t.db.Exec(\"DROP DATABASE IF EXISTS normalized_realm\")\n\t\thcl := `\nschema \"public\" {}\nenum \"status\" {\n  schema = schema.public\n  values = [\"active\", \"inactive\"]\n}\n\ntable \"users\" {\n  schema = schema.public\n  column \"id\" { type = serial }\n  column \"e\"  { type = enum.status }\n  column \"ae\" { type = sql(\"public.status[]\") }\n}\n\nschema \"other\" {}\ntable \"posts\" {\n  schema = schema.other\n  column \"id\" { type = integer }\n}\n\ntable \"with_default\" {\n  schema = schema.other\n  column \"name\" {\n    type = varchar\n\tdefault = sql(\"lower('Hello')\")\n  }\n}\n`\n\t\terr = os.WriteFile(filepath.Join(dir, \"schema.hcl\"), []byte(hcl), 0600)\n\t\trequire.NoError(t, err)\n\t\tout, err := exec.Command(\n\t\t\tbin, \"schema\", \"inspect\",\n\t\t\t\"--url\", fmt.Sprintf(\"file://%s\", filepath.Join(dir, \"schema.hcl\")),\n\t\t\t\"--dev-url\", fmt.Sprintf(\"postgres://postgres:pass@localhost:%d/normalized_realm?sslmode=disable\", t.port),\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, `table \"posts\" {\n  schema = schema.other\n  column \"id\" {\n    null = false\n    type = integer\n  }\n}\ntable \"with_default\" {\n  schema = schema.other\n  column \"name\" {\n    null    = false\n    type    = character_varying\n    default = sql(\"lower('Hello'::text)\")\n  }\n}\ntable \"users\" {\n  schema = schema.public\n  column \"id\" {\n    null = false\n    type = serial\n  }\n  column \"e\" {\n    null = false\n    type = enum.status\n  }\n  column \"ae\" {\n    null = false\n    type = sql(\"public.status[]\")\n  }\n}\nenum \"status\" {\n  schema = schema.public\n  values = [\"active\", \"inactive\"]\n}\nschema \"other\" {\n}\nschema \"public\" {\n  comment = \"standard public schema\"\n}\n`, string(out))\n\t\terr = t.drv.CheckClean(context.Background(), nil)\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc TestPostgres_MigrateDiffRealm(t *testing.T) {\n\tbin := cliPath(t)\n\tpgRun(t, func(t *pgTest) {\n\t\tdir := t.TempDir()\n\t\t_, err := t.db.Exec(\"CREATE DATABASE migrate_diff\")\n\t\trequire.NoError(t, err)\n\t\tdefer t.db.Exec(\"DROP DATABASE IF EXISTS migrate_diff\")\n\n\t\thcl := `\nschema \"public\" {}\ntable \"users\" {\n\tschema = schema.public\n\tcolumn \"id\" { type = integer }\n}\nschema \"other\" {}\ntable \"posts\" {\n\tschema = schema.other\n\tcolumn \"id\" { type = integer }\n}\n`\n\t\terr = os.WriteFile(filepath.Join(dir, \"schema.hcl\"), []byte(hcl), 0600)\n\t\tdiff := func(name string) string {\n\t\t\tout, err := exec.Command(\n\t\t\t\tbin, \"migrate\", \"diff\", name,\n\t\t\t\t\"--dir\", fmt.Sprintf(\"file://%s\", filepath.Join(dir, \"migrations\")),\n\t\t\t\t\"--to\", fmt.Sprintf(\"file://%s\", filepath.Join(dir, \"schema.hcl\")),\n\t\t\t\t\"--dev-url\", fmt.Sprintf(\"postgres://postgres:pass@localhost:%d/migrate_diff?sslmode=disable\", t.port),\n\t\t\t).CombinedOutput()\n\t\t\trequire.NoError(t, err, string(out))\n\t\t\treturn strings.TrimSpace(string(out))\n\t\t}\n\t\trequire.Empty(t, diff(\"initial\"))\n\n\t\t// Expect one file and read its contents.\n\t\tfiles, err := os.ReadDir(filepath.Join(dir, \"migrations\"))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 2, len(files))\n\t\trequire.Equal(t, \"atlas.sum\", files[1].Name())\n\t\tb, err := os.ReadFile(filepath.Join(dir, \"migrations\", files[0].Name()))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t,\n\t\t\t`-- Add new schema named \"other\"\nCREATE SCHEMA \"other\";\n-- Create \"users\" table\nCREATE TABLE \"public\".\"users\" (\"id\" integer NOT NULL);\n-- Create \"posts\" table\nCREATE TABLE \"other\".\"posts\" (\"id\" integer NOT NULL);\n`, string(b))\n\t\trequire.Equal(t, \"The migration directory is synced with the desired state, no changes to be made\", diff(\"no_change\"))\n\n\t\t// Append a change to the schema and expect a migration to be created.\n\t\thcl += `\ntable \"other\" \"users\" {\n\tschema = schema.other\n\tcolumn \"id\" { type = integer }\n}`\n\t\terr = os.WriteFile(filepath.Join(dir, \"schema.hcl\"), []byte(hcl), 0600)\n\t\trequire.Empty(t, diff(\"second\"))\n\t\trequire.Equal(t, \"The migration directory is synced with the desired state, no changes to be made\", diff(\"no_change\"))\n\t\tfiles, err = os.ReadDir(filepath.Join(dir, \"migrations\"))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 3, len(files), dir)\n\t\tb, err = os.ReadFile(filepath.Join(dir, \"migrations\", files[1].Name()))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t,\n\t\t\t`-- Create \"users\" table\nCREATE TABLE \"other\".\"users\" (\"id\" integer NOT NULL);\n`, string(b))\n\t})\n}\n\nfunc TestPostgres_SchemaDiff(t *testing.T) {\n\tbin := cliPath(t)\n\tpgRun(t, func(t *pgTest) {\n\t\tdir := t.TempDir()\n\t\t_, err := t.db.Exec(\"CREATE DATABASE test1\")\n\t\trequire.NoError(t, err)\n\t\tt.Cleanup(func() {\n\t\t\t_, err := t.db.Exec(\"DROP DATABASE IF EXISTS test1\")\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t\t_, err = t.db.Exec(\"CREATE DATABASE test2\")\n\t\trequire.NoError(t, err)\n\t\tt.Cleanup(func() {\n\t\t\t_, err = t.db.Exec(\"DROP DATABASE IF EXISTS test2\")\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\tdiff := func(db1, db2 string) string {\n\t\t\tout, err := exec.Command(\n\t\t\t\tbin, \"schema\", \"diff\",\n\t\t\t\t\"--from\", fmt.Sprintf(\"postgres://postgres:pass@localhost:%d/%s\", t.port, db1),\n\t\t\t\t\"--to\", fmt.Sprintf(\"postgres://postgres:pass@localhost:%d/%s\", t.port, db2),\n\t\t\t).CombinedOutput()\n\t\t\trequire.NoError(t, err, string(out))\n\t\t\treturn strings.TrimSpace(string(out))\n\t\t}\n\t\t// Diff a database with itself.\n\t\trequire.Equal(t, \"Schemas are synced, no changes to be made.\", diff(\"test1?sslmode=disable\", \"test2?sslmode=disable\"))\n\n\t\t// Create schemas on test2 database.\n\t\thcl := `\nschema \"public\" {\n  comment = \"standard public schema\"\n}\ntable \"users\" {\n\tschema = schema.public\n\tcolumn \"id\" { type = integer }\n}\nschema \"other\" {}\ntable \"posts\" {\n\tschema = schema.other\n\tcolumn \"id\" { type = integer }\n}\n`\n\t\terr = os.WriteFile(filepath.Join(dir, \"schema.hcl\"), []byte(hcl), 0600)\n\t\trequire.NoError(t, err)\n\t\tout, err := exec.Command(\n\t\t\tbin, \"schema\", \"apply\",\n\t\t\t\"-u\", fmt.Sprintf(\"postgres://postgres:pass@localhost:%d/test2?sslmode=disable\", t.port),\n\t\t\t\"-f\", filepath.Join(dir, \"schema.hcl\"),\n\t\t\t\"--auto-approve\",\n\t\t).CombinedOutput()\n\t\trequire.NoError(t, err, string(out))\n\n\t\t// Diff a database with different one.\n\t\trequire.Equal(t, `-- Add new schema named \"other\"\nCREATE SCHEMA \"other\";\n-- Create \"users\" table\nCREATE TABLE \"public\".\"users\" (\"id\" integer NOT NULL);\n-- Create \"posts\" table\nCREATE TABLE \"other\".\"posts\" (\"id\" integer NOT NULL);`, diff(\"test1?sslmode=disable\", \"test2?sslmode=disable\"))\n\n\t\t// Diffing schema should both tables and comments (from 'public' to 'other').\n\t\trequire.Equal(t, `-- Create \"users\" table\nCREATE TABLE \"users\" (\"id\" integer NOT NULL);\n-- Drop \"posts\" table\nDROP TABLE \"posts\";`, diff(\"test2?sslmode=disable&search_path=other\", \"test2?sslmode=disable&search_path=public\"))\n\t\t// diff between schema and database\n\t\tout, err = exec.Command(\n\t\t\tbin, \"schema\", \"diff\",\n\t\t\t\"--from\", fmt.Sprintf(\"postgres://postgres:pass@localhost:%d/test2?sslmode=disable\", t.port),\n\t\t\t\"--to\", fmt.Sprintf(\"postgres://postgres:pass@localhost:%d/test2?sslmode=disable&search_path=public\", t.port),\n\t\t).CombinedOutput()\n\t\trequire.Error(t, err, string(out))\n\t\trequire.Equal(t, \"Error: cannot diff a schema \\\"public\\\" with a database connection. See: https://atlasgo.io/url\\n\", string(out))\n\t})\n}\n\nfunc TestPostgres_DefaultsHCL(t *testing.T) {\n\tn := \"atlas_defaults\"\n\tpgRun(t, func(t *pgTest) {\n\t\tddl := `\ncreate table atlas_defaults\n(\n\tstring varchar(255) default 'hello_world',\n\tquoted varchar(100) default 'never say \"never\"',\n\ttBit bit(10) default b'10101',\n\tts timestamp default CURRENT_TIMESTAMP,\n\ttstz timestamp with time zone default CURRENT_TIMESTAMP,\n\tnumber int default 42\n)\n`\n\t\tt.dropTables(n)\n\t\t_, err := t.db.Exec(ddl)\n\t\trequire.NoError(t, err)\n\t\trealm := t.loadRealm()\n\t\tspec, err := postgres.MarshalHCL(realm.Schemas[0])\n\t\trequire.NoError(t, err)\n\t\tvar s schema.Schema\n\t\terr = postgres.EvalHCLBytes(spec, &s, nil)\n\t\trequire.NoError(t, err)\n\t\tt.dropTables(n)\n\t\tt.applyHcl(string(spec))\n\t\tensureNoChange(t, realm.Schemas[0].Tables[0])\n\t})\n}\n\nfunc TestPostgres_Sanity(t *testing.T) {\n\tn := \"atlas_types_sanity\"\n\tddl := `\nDROP TYPE IF EXISTS address;\nCREATE TYPE address AS (city VARCHAR(90), street VARCHAR(90));\ncreate table atlas_types_sanity\n(\n    \"tBit\"                 bit(10)                     default b'100'                                   null,\n    \"tBitVar\"              bit varying(10)             default b'100'                                   null,\n    \"tBoolean\"             boolean                     default false                                not null,\n    \"tBool\"                bool                        default false                                not null,\n    \"tBytea\"               bytea                       default E'\\\\001'                             not null,\n    \"tCharacter\"           character(10)               default 'atlas'                                  null,\n    \"tChar\"                char(10)                    default 'atlas'                                  null,\n    \"tCharVar\"             character varying(10)       default 'atlas'                                  null,\n    \"tVarChar\"             varchar(10)                 default 'atlas'                                  null,\n    \"tText\"                text                        default 'atlas'                                  null,\n    \"tSmallInt\"            smallint                    default '10'                                     null,\n    \"tInteger\"             integer                     default '10'                                     null,\n    \"tBigInt\"              bigint                      default '10'                                     null,\n    \"tInt\"                 int                         default '10'                                     null,\n    \"tInt2\"                int2                        default '10'                                     null,\n    \"tInt4\"                int4                        default '10'                                     null,\n    \"tInt8\"                int8                        default '10'                                     null,\n    \"tCIDR\"                cidr                        default '127.0.0.1'                              null,\n    \"tInet\"                inet                        default '127.0.0.1'                              null,\n    \"tMACAddr\"             macaddr                     default '08:00:2b:01:02:03'                      null,\n    \"tMACAddr8\"            macaddr8                    default '08:00:2b:01:02:03:04:05'                null,\n    \"tCircle\"              circle                      default                                          null,\n    \"tLine\"                line                        default                                          null,\n    \"tLseg\"                lseg                        default                                          null,\n    \"tBox\"                 box                         default                                          null,\n    \"tPath\"                path                        default                                          null,\n    \"tPoint\"               point                       default                                          null,\n    \"tDate\"                date                        default current_date                             null,\n    \"tTime\"                time                        default current_time                             null,\n    \"tTimeWTZ\"             time with time zone         default current_time                             null,\n    \"tTimeWOTZ\"            time without time zone      default current_time                             null,\n    \"tTimestamp\"           timestamp                   default now()                                    null,\n    \"tTimestampTZ\"         timestamptz                 default now()                                    null,\n    \"tTimestampWTZ\"        timestamp with time zone    default now()                                    null,\n    \"tTimestampWOTZ\"       timestamp without time zone default now()                                    null,\n    \"tTimestampPrec\"       timestamp(4)                default now()                                    null,\n    \"tDouble\"              double precision            default 0                                        null,\n    \"tReal\"                real                        default 0                                        null,\n    \"tFloat8\"              float8                      default 0                                        null,\n    \"tFloat4\"              float4                      default 0                                        null,\n    \"tNumeric\"             numeric                     default 0                                        null,\n    \"tDecimal\"             decimal                     default 0                                        null,\n    \"tSmallSerial\"         smallserial                                                                      ,\n    \"tSerial\"              serial                                                                           ,\n    \"tBigSerial\"           bigserial                                                                        ,\n    \"tSerial2\"             serial2                                                                          ,\n    \"tSerial4\"             serial4                                                                          ,\n    \"tSerial8\"             serial8                                                                          ,\n    \"tArray\"               text[10][10]                 default '{}'                                    null,\n    \"tXML\"                 xml                          default '<a>foo</a>'                            null,\n    \"tJSON\"                json                         default '{\"key\":\"value\"}'                       null,\n    \"tJSONB\"               jsonb                        default '{\"key\":\"value\"}'                       null,\n    \"tUUID\"                uuid                         default  'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11' null,\n    \"tMoney\"               money                        default  18                                     null,\n    \"tInterval\"            interval                     default '4 hours'                               null,\n    \"tUserDefined\"         address                      default '(\"ab\",\"cd\")'                           null\n);\n`\n\tpgRun(t, func(t *pgTest) {\n\t\tt.dropTables(n)\n\t\t_, err := t.db.Exec(ddl)\n\t\trequire.NoError(t, err)\n\t\trealm := t.loadRealm()\n\t\trequire.Len(t, realm.Schemas, 1)\n\t\tts, ok := realm.Schemas[0].Table(n)\n\t\trequire.True(t, ok)\n\t\trequire.Len(t, ts.Attrs, 1)\n\t\trequire.IsType(t, &postgres.OID{}, ts.Attrs[0])\n\t\tfor _, c := range ts.Columns {\n\t\t\tc.Attrs = nil // Skip comparing attributes, due to ent/oss differences.\n\t\t}\n\t\texpected := schema.Table{\n\t\t\tName:   n,\n\t\t\tAttrs:  ts.Attrs,\n\t\t\tSchema: realm.Schemas[0],\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBit\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &postgres.BitType{T: \"bit\", Len: 10}, Raw: \"bit\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: t.valueByVersion(map[string]string{\"postgres10\": \"B'100'::\\\"bit\\\"\"}, \"'100'::\\\"bit\\\"\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBitVar\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &postgres.BitType{T: \"bit varying\", Len: 10}, Raw: \"bit varying\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: t.valueByVersion(map[string]string{\"postgres10\": \"B'100'::\\\"bit\\\"\"}, \"'100'::\\\"bit\\\"\")},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBoolean\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}, Raw: \"boolean\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{V: \"false\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBool\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}, Raw: \"boolean\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{V: \"false\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBytea\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.BinaryType{T: \"bytea\"}, Raw: \"bytea\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{V: \"'\\\\x01'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tCharacter\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.StringType{T: \"character\", Size: 10}, Raw: \"character\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"'atlas'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tChar\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.StringType{T: \"character\", Size: 10}, Raw: \"character\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"'atlas'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tCharVar\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.StringType{T: \"character varying\", Size: 10}, Raw: \"character varying\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"'atlas'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tVarChar\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.StringType{T: \"character varying\", Size: 10}, Raw: \"character varying\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"'atlas'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tText\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Raw: \"text\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"'atlas'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tSmallInt\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"smallint\"}, Raw: \"smallint\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInteger\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Raw: \"integer\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tBigInt\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}, Raw: \"bigint\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInt\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Raw: \"integer\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInt2\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"smallint\"}, Raw: \"smallint\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInt4\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Raw: \"integer\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInt8\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}, Raw: \"bigint\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tCIDR\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &postgres.NetworkType{T: \"cidr\"}, Raw: \"cidr\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"'127.0.0.1/32'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tInet\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &postgres.NetworkType{T: \"inet\"}, Raw: \"inet\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"'127.0.0.1'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tMACAddr\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &postgres.NetworkType{T: \"macaddr\"}, Raw: \"macaddr\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"'08:00:2b:01:02:03'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tMACAddr8\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &postgres.NetworkType{T: \"macaddr8\"}, Raw: \"macaddr8\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"'08:00:2b:01:02:03:04:05'\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tCircle\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"circle\"}, Raw: \"circle\", Null: true},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tLine\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"line\"}, Raw: \"line\", Null: true},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tLseg\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"lseg\"}, Raw: \"lseg\", Null: true},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tBox\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"box\"}, Raw: \"box\", Null: true},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tPath\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"path\"}, Raw: \"path\", Null: true},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tPoint\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.SpatialType{T: \"point\"}, Raw: \"point\", Null: true},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tDate\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"date\"}, Raw: \"date\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"CURRENT_DATE\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTime\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"time without time zone\", Precision: intp(6)}, Raw: \"time without time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"CURRENT_TIME\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimeWTZ\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"time with time zone\", Precision: intp(6)}, Raw: \"time with time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"CURRENT_TIME\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimeWOTZ\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"time without time zone\", Precision: intp(6)}, Raw: \"time without time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"CURRENT_TIME\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimestamp\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp without time zone\", Precision: intp(6)}, Raw: \"timestamp without time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now()\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimestampTZ\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp with time zone\", Precision: intp(6)}, Raw: \"timestamp with time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now()\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimestampWTZ\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp with time zone\", Precision: intp(6)}, Raw: \"timestamp with time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now()\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimestampWOTZ\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp without time zone\", Precision: intp(6)}, Raw: \"timestamp without time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now()\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tTimestampPrec\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp without time zone\", Precision: intp(4)}, Raw: \"timestamp without time zone\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now()\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tDouble\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.FloatType{T: \"double precision\", Precision: 53}, Raw: \"double precision\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"0\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tReal\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.FloatType{T: \"real\", Precision: 24}, Raw: \"real\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"0\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tFloat8\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.FloatType{T: \"double precision\", Precision: 53}, Raw: \"double precision\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"0\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tFloat4\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.FloatType{T: \"real\", Precision: 24}, Raw: \"real\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"0\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tNumeric\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 0}, Raw: \"numeric\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"0\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"tDecimal\",\n\t\t\t\t\tType:    &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 0}, Raw: \"numeric\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{V: \"0\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSmallSerial\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.SerialType{T: \"smallserial\", SequenceName: \"atlas_types_sanity_tSmallSerial_seq\"}, Raw: \"smallserial\", Null: false},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSerial\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.SerialType{T: \"serial\", SequenceName: \"atlas_types_sanity_tSerial_seq\"}, Raw: \"serial\", Null: false},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tBigSerial\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.SerialType{T: \"bigserial\", SequenceName: \"atlas_types_sanity_tBigSerial_seq\"}, Raw: \"bigserial\", Null: false},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSerial2\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.SerialType{T: \"smallserial\", SequenceName: \"atlas_types_sanity_tSerial2_seq\"}, Raw: \"smallserial\", Null: false},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSerial4\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.SerialType{T: \"serial\", SequenceName: \"atlas_types_sanity_tSerial4_seq\"}, Raw: \"serial\", Null: false},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSerial8\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.SerialType{T: \"bigserial\", SequenceName: \"atlas_types_sanity_tSerial8_seq\"}, Raw: \"bigserial\", Null: false},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tArray\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.ArrayType{Type: &schema.StringType{T: \"text\"}, T: \"text[]\"}, Raw: \"ARRAY\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'{}'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tXML\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.XMLType{T: \"xml\"}, Raw: \"xml\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'<a>foo</a>'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tJSON\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.JSONType{T: \"json\"}, Raw: \"json\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'{\\\"key\\\":\\\"value\\\"}'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tJSONB\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.JSONType{T: \"jsonb\"}, Raw: \"jsonb\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'{\\\"key\\\": \\\"value\\\"}'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tUUID\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.UUIDType{T: \"uuid\"}, Raw: \"uuid\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tMoney\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.CurrencyType{T: \"money\"}, Raw: \"money\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"18\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tInterval\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.IntervalType{T: \"interval\", Precision: intp(6)}, Raw: \"interval\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"'04:00:00'::interval\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tUserDefined\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &postgres.UserDefinedType{T: \"public.address\", C: \"c\"}, Raw: \"USER-DEFINED\", Null: true},\n\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\tX: \"'(ab,cd)'::public.address\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\trequire.EqualValues(t, &expected, ts)\n\t})\n\tt.Run(\"ImplicitIndexes\", func(t *testing.T) {\n\t\tpgRun(t, func(t *pgTest) {\n\t\t\ttestImplicitIndexes(t, t.db)\n\t\t})\n\t})\n}\n\nfunc (t *pgTest) url(schema string) string {\n\treturn t.dbURL(\"test\", schema)\n}\n\nfunc (t *pgTest) dbURL(db, schema string) string {\n\tvar (\n\t\tformat = \"postgres://postgres:pass@localhost:%d/%s?sslmode=disable\"\n\t\targs   = []any{t.port, db}\n\t)\n\tif schema != \"\" {\n\t\tformat += \"&search_path=%s\"\n\t\targs = append(args, schema)\n\t}\n\treturn fmt.Sprintf(format, args...)\n}\n\nfunc (t *pgTest) driver() migrate.Driver {\n\treturn t.drv\n}\n\nfunc (t *pgTest) revisionsStorage() migrate.RevisionReadWriter {\n\treturn t.rrw\n}\n\nfunc (t *pgTest) applyHcl(spec string) {\n\trealm := t.loadRealm()\n\tvar desired schema.Schema\n\terr := postgres.EvalHCLBytes([]byte(spec), &desired, nil)\n\trequire.NoError(t, err)\n\texisting := realm.Schemas[0]\n\tdiff, err := t.drv.SchemaDiff(existing, &desired)\n\trequire.NoError(t, err)\n\terr = t.drv.ApplyChanges(context.Background(), diff)\n\trequire.NoError(t, err)\n}\n\nfunc (t *pgTest) valueByVersion(values map[string]string, defaults string) string {\n\tif v, ok := values[t.version]; ok {\n\t\treturn v\n\t}\n\treturn defaults\n}\n\nfunc (t *pgTest) loadRealm() *schema.Realm {\n\tr, err := t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\tSchemas: []string{\"public\"},\n\t\tMode:    schema.InspectSchemas | schema.InspectTables | schema.InspectTypes,\n\t})\n\trequire.NoError(t, err)\n\treturn r\n}\n\nfunc (t *pgTest) loadUsers() *schema.Table {\n\treturn t.loadTable(\"users\")\n}\n\nfunc (t *pgTest) loadPosts() *schema.Table {\n\treturn t.loadTable(\"posts\")\n}\n\nfunc (t *pgTest) loadTable(name string) *schema.Table {\n\trealm := t.loadRealm()\n\trequire.Len(t, realm.Schemas, 1)\n\ttable, ok := realm.Schemas[0].Table(name)\n\trequire.True(t, ok)\n\treturn table\n}\n\nfunc (t *pgTest) users() *schema.Table {\n\tusersT := &schema.Table{\n\t\tName:   \"users\",\n\t\tSchema: t.realm().Schemas[0],\n\t\tColumns: []*schema.Column{\n\t\t\t{\n\t\t\t\tName:  \"id\",\n\t\t\t\tType:  &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t\tAttrs: []schema.Attr{&postgres.Identity{}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"x\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t},\n\t\t},\n\t}\n\tusersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}\n\treturn usersT\n}\n\nfunc (t *pgTest) posts() *schema.Table {\n\tusersT := t.users()\n\tpostsT := &schema.Table{\n\t\tName:   \"posts\",\n\t\tSchema: t.realm().Schemas[0],\n\t\tColumns: []*schema.Column{\n\t\t\t{\n\t\t\t\tName:  \"id\",\n\t\t\t\tType:  &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t\tAttrs: []schema.Attr{&postgres.Identity{}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"author_id\",\n\t\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"ctime\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"timestamp\", Type: &schema.TimeType{T: \"timestamp\"}},\n\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\tX: \"CURRENT_TIMESTAMP\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tAttrs: []schema.Attr{\n\t\t\t&schema.Comment{Text: \"posts comment\"},\n\t\t},\n\t}\n\tpostsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}\n\tpostsT.Indexes = []*schema.Index{\n\t\t{Name: \"author_id\", Parts: []*schema.IndexPart{{C: postsT.Columns[1]}}},\n\t\t{Name: \"id_author_id_unique\", Unique: true, Parts: []*schema.IndexPart{{C: postsT.Columns[1]}, {C: postsT.Columns[0]}}},\n\t}\n\tpostsT.ForeignKeys = []*schema.ForeignKey{\n\t\t{Symbol: \"author_id\", Table: postsT, Columns: postsT.Columns[1:2], RefTable: usersT, RefColumns: usersT.Columns[:1], OnDelete: schema.NoAction},\n\t}\n\treturn postsT\n}\n\nfunc (t *pgTest) realm() *schema.Realm {\n\tr := &schema.Realm{\n\t\tSchemas: []*schema.Schema{\n\t\t\t{\n\t\t\t\tName: \"public\",\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Comment{Text: \"standard public schema\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tr.Schemas[0].Realm = r\n\treturn r\n}\n\nfunc (t *pgTest) diff(t1, t2 *schema.Table) []schema.Change {\n\tchanges, err := t.drv.TableDiff(t1, t2)\n\trequire.NoError(t, err)\n\treturn changes\n}\n\nfunc (t *pgTest) migrate(changes ...schema.Change) {\n\terr := t.drv.ApplyChanges(context.Background(), changes)\n\trequire.NoError(t, err)\n}\n\nfunc (t *pgTest) dropTables(names ...string) {\n\tt.Cleanup(func() {\n\t\t_, err := t.db.Exec(\"DROP TABLE IF EXISTS \" + strings.Join(names, \", \"))\n\t\trequire.NoError(t.T, err, \"drop tables %q\", names)\n\t})\n}\n\nfunc (t *pgTest) dropSchemas(names ...string) {\n\tt.Cleanup(func() {\n\t\t_, err := t.db.Exec(\"DROP SCHEMA IF EXISTS \" + strings.Join(names, \", \") + \" CASCADE\")\n\t\trequire.NoError(t.T, err, \"drop schema %q\", names)\n\t})\n}\n"
  },
  {
    "path": "internal/integration/script_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage integration\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"unicode\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/mysql\"\n\t\"ariga.io/atlas/sql/postgres\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t\"ariga.io/atlas/sql/sqlite\"\n\n\t\"github.com/pkg/diff\"\n\t\"github.com/rogpeppe/go-internal/testscript\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestMySQL_Script(t *testing.T) {\n\tmyRun(t, func(t *myTest) {\n\t\ttestscript.Run(t.T, testscript.Params{\n\t\t\tDir:   \"testdata/mysql\",\n\t\t\tSetup: t.setupScript,\n\t\t\tCmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){\n\t\t\t\t\"only\":        cmdOnly,\n\t\t\t\t\"apply\":       t.cmdApply,\n\t\t\t\t\"exist\":       t.cmdExist,\n\t\t\t\t\"synced\":      t.cmdSynced,\n\t\t\t\t\"cmphcl\":      t.cmdCmpHCL,\n\t\t\t\t\"cmpshow\":     t.cmdCmpShow,\n\t\t\t\t\"cmpmig\":      t.cmdCmpMig,\n\t\t\t\t\"execsql\":     t.cmdExec,\n\t\t\t\t\"atlas\":       t.cmdCLI,\n\t\t\t\t\"clearSchema\": t.clearSchema,\n\t\t\t\t\"validJSON\":   validJSON,\n\t\t\t},\n\t\t})\n\t})\n}\n\nfunc TestPostgres_Script(t *testing.T) {\n\tpgRun(t, func(t *pgTest) {\n\t\ttestscript.Run(t.T, testscript.Params{\n\t\t\tDir:   \"testdata/postgres\",\n\t\t\tSetup: t.setupScript,\n\t\t\tCmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){\n\t\t\t\t\"only\":        cmdOnly,\n\t\t\t\t\"apply\":       t.cmdApply,\n\t\t\t\t\"exist\":       t.cmdExist,\n\t\t\t\t\"synced\":      t.cmdSynced,\n\t\t\t\t\"cmphcl\":      t.cmdCmpHCL,\n\t\t\t\t\"cmpshow\":     t.cmdCmpShow,\n\t\t\t\t\"cmpmig\":      t.cmdCmpMig,\n\t\t\t\t\"execsql\":     t.cmdExec,\n\t\t\t\t\"atlas\":       t.cmdCLI,\n\t\t\t\t\"clearSchema\": t.clearSchema,\n\t\t\t},\n\t\t})\n\t})\n}\n\nfunc TestSQLite_Script(t *testing.T) {\n\ttt := &liteTest{T: t}\n\ttestscript.Run(t, testscript.Params{\n\t\tDir:   \"testdata/sqlite\",\n\t\tSetup: tt.setupScript,\n\t\tCmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){\n\t\t\t\"apply\":       tt.cmdApply,\n\t\t\t\"exist\":       tt.cmdExist,\n\t\t\t\"synced\":      tt.cmdSynced,\n\t\t\t\"cmphcl\":      tt.cmdCmpHCL,\n\t\t\t\"cmpshow\":     tt.cmdCmpShow,\n\t\t\t\"cmpmig\":      tt.cmdCmpMig,\n\t\t\t\"execsql\":     tt.cmdExec,\n\t\t\t\"atlas\":       tt.cmdCLI,\n\t\t\t\"clearSchema\": tt.clearSchema,\n\t\t},\n\t})\n}\n\nvar keyT struct{}\n\nfunc (t *myTest) setupScript(env *testscript.Env) error {\n\tattrs := t.defaultAttrs()\n\tenv.Setenv(\"version\", t.version)\n\tenv.Setenv(\"charset\", attrs[0].(*schema.Charset).V)\n\tenv.Setenv(\"collate\", attrs[1].(*schema.Collation).V)\n\tif err := replaceDBURL(env, t.url(\"\")); err != nil {\n\t\treturn err\n\t}\n\treturn setupScript(env, t.db,\n\t\t\"CREATE SCHEMA IF NOT EXISTS %s\",\n\t\t\"DROP SCHEMA IF EXISTS %s\",\n\t\tfunc(tt testing.TB, schema string) migrate.Driver {\n\t\t\tdev, err := sqlclient.Open(context.Background(), fmt.Sprintf(\"mysql://root:pass@localhost:%d/%s\", t.port, schema))\n\t\t\trequire.NoError(tt, err)\n\t\t\ttt.Cleanup(func() { require.NoError(tt, dev.Close()) })\n\t\t\treturn dev.Driver\n\t\t})\n}\n\nfunc replaceDBURL(env *testscript.Env, url string) error {\n\t// Set the workdir in the test atlas.hcl file.\n\tprojectFile := filepath.Join(env.WorkDir, \"atlas.hcl\")\n\tif b, err := os.ReadFile(projectFile); err == nil {\n\t\trep := strings.ReplaceAll(string(b), \"URL\", url)\n\t\treturn os.WriteFile(projectFile, []byte(rep), 0600)\n\t}\n\treturn nil\n}\n\nfunc (t *pgTest) setupScript(env *testscript.Env) error {\n\tenv.Setenv(\"version\", t.version)\n\tu := strings.ReplaceAll(t.url(\"\"), \"/test\", \"/\")\n\tif err := replaceDBURL(env, u); err != nil {\n\t\treturn err\n\t}\n\treturn setupScript(env, t.db,\n\t\t\"CREATE SCHEMA IF NOT EXISTS %s\",\n\t\t\"DROP SCHEMA IF EXISTS %s CASCADE\",\n\t\tfunc(tt testing.TB, schema string) migrate.Driver {\n\t\t\tdev, err := sqlclient.Open(context.Background(), fmt.Sprintf(\"postgres://postgres:pass@localhost:%d/test?search_path=%s&sslmode=disable\", t.port, schema))\n\t\t\trequire.NoError(tt, err)\n\t\t\ttt.Cleanup(func() { require.NoError(tt, dev.Close()) })\n\t\t\treturn dev.Driver\n\t\t})\n}\n\nfunc setupScript(env *testscript.Env, db *sql.DB, createCmd, dropCmd string, open func(testing.TB, string) migrate.Driver) error {\n\tctx := context.Background()\n\tconn, err := db.Conn(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tname := strings.ReplaceAll(filepath.Base(env.WorkDir), \"-\", \"_\")\n\tdevname := fmt.Sprintf(\"%s_dev\", name)\n\tenv.Setenv(\"db\", name)\n\tenv.Setenv(\"dev\", devname)\n\tif _, err := conn.ExecContext(ctx, fmt.Sprintf(createCmd, name)); err != nil {\n\t\treturn err\n\t}\n\tif _, err := conn.ExecContext(ctx, fmt.Sprintf(createCmd, devname)); err != nil {\n\t\treturn err\n\t}\n\t// Env has a T() method that returns the *testing.T.\n\t// We need to cast it to the testing.TB interface\n\t// to be able to use the Cleanup method.\n\ttt := env.T().(testing.TB)\n\ttt.Cleanup(func() {\n\t\tif _, err := conn.ExecContext(ctx, fmt.Sprintf(dropCmd, name)); err != nil {\n\t\t\ttt.Fatal(err)\n\t\t}\n\t\tif _, err := conn.ExecContext(ctx, fmt.Sprintf(dropCmd, devname)); err != nil {\n\t\t\ttt.Fatal(err)\n\t\t}\n\t\tif err := conn.Close(); err != nil {\n\t\t\ttt.Fatal(err)\n\t\t}\n\t})\n\t// Dev-driver per testscript schema to allow concurrent tests.\n\tenv.Values[\"drv\"] = open(tt, name)\n\tenv.Values[\"dev\"] = open(tt, devname)\n\t// Store the testscript.T for later use.\n\t// See \"only\" function below.\n\tenv.Values[keyT] = env.T()\n\tenv.Setenv(atlasPathKey, cliPath(tt))\n\treturn nil\n}\n\nvar (\n\tkeyDB  *sql.DB\n\tkeyDrv *sqlite.Driver\n)\n\nconst atlasPathKey = \"cli.atlas\"\n\nfunc (t *liteTest) setupScript(env *testscript.Env) error {\n\tdb, err := sql.Open(\"sqlite3\", fmt.Sprintf(\"file:%s?cache=shared&_fk=1\",\n\t\tfilepath.Join(env.WorkDir, \"atlas.sqlite\")))\n\trequire.NoError(t, err)\n\tenv.Defer(func() {\n\t\trequire.NoError(t, db.Close())\n\t})\n\tdrv, err := sqlite.Open(db)\n\trequire.NoError(t, err)\n\tenv.Setenv(\"db\", \"main\")\n\t// Attach connection and driver to the\n\t// environment as tests run in parallel.\n\tenv.Values[keyDB] = db\n\tenv.Values[keyDrv] = drv\n\tenv.Setenv(atlasPathKey, cliPath(t.T))\n\t// Set the workdir in the test atlas.hcl file.\n\tprojectFile := filepath.Join(env.WorkDir, \"atlas.hcl\")\n\tif b, err := os.ReadFile(projectFile); err == nil {\n\t\trep := strings.ReplaceAll(string(b), \"URL\",\n\t\t\tfmt.Sprintf(\"sqlite://file:%s/atlas.sqlite?cache=shared&_fk=1\", env.WorkDir))\n\t\treturn os.WriteFile(projectFile, []byte(rep), 0600)\n\t}\n\treturn nil\n}\n\n// cmdOnly executes only tests that their driver version matches the given pattern.\n// For example, \"only 8\" or \"only 8 maria*\"\nfunc cmdOnly(ts *testscript.TestScript, neg bool, args []string) {\n\tver := ts.Getenv(\"version\")\n\tfor i := range args {\n\t\tre, rerr := regexp.Compile(`(?mi)` + args[i])\n\t\tts.Check(rerr)\n\t\tif !neg == re.MatchString(ver) {\n\t\t\treturn\n\t\t}\n\t}\n\t// This is not an elegant way to get the created testing.T for the script,\n\t// but we need some workaround to get it in order to skip specific tests.\n\tts.Value(keyT).(testscript.T).Skip(\"skip version\", ver)\n}\n\nfunc (t *myTest) cmdCmpShow(ts *testscript.TestScript, _ bool, args []string) {\n\tcmdCmpShow(ts, args, func(schema, name string) (string, error) {\n\t\tvar create string\n\t\tif err := t.db.QueryRow(fmt.Sprintf(\"SHOW CREATE TABLE `%s`.`%s`\", schema, name)).Scan(&name, &create); err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\ti := strings.LastIndexByte(create, ')')\n\t\tcreate, opts := create[:i+1], strings.Fields(create[i+1:])\n\t\tfor _, opt := range opts {\n\t\t\tswitch strings.Split(opt, \"=\")[0] {\n\t\t\t// Keep only options that are relevant for the tests.\n\t\t\tcase \"AUTO_INCREMENT\", \"COMMENT\":\n\t\t\t\tcreate += \" \" + opt\n\t\t\t}\n\t\t}\n\t\treturn create, nil\n\t})\n}\n\nfunc (t *pgTest) cmdCmpShow(ts *testscript.TestScript, _ bool, args []string) {\n\tcmdCmpShow(ts, args, func(schema, name string) (string, error) {\n\t\tbuf, err := exec.Command(\"docker\", \"ps\", \"-qa\", \"-f\", fmt.Sprintf(\"publish=%d\", t.port)).CombinedOutput()\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"get container id %q: %v\", buf, err)\n\t\t}\n\t\tbuf = bytes.TrimSpace(buf)\n\t\tif len(bytes.Split(buf, []byte(\"\\n\"))) > 1 {\n\t\t\treturn \"\", fmt.Errorf(\"multiple container ids found: %q\", buf)\n\t\t}\n\t\tcmd := exec.Command(\"docker\", \"exec\", string(buf), \"psql\", \"-U\", \"postgres\", \"-d\", \"test\", \"-c\", fmt.Sprintf(`\\d %s.%s`, schema, name))\n\t\t// Use \"cmd.String\" to debug command.\n\t\tbuf, err = cmd.CombinedOutput()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tlines := strings.Split(string(buf), \"\\n\")\n\t\tfor i := range lines {\n\t\t\tlines[i] = strings.TrimRightFunc(lines[i], unicode.IsSpace)\n\t\t}\n\t\treturn strings.Join(lines, \"\\n\"), err\n\t})\n}\n\nfunc (t *liteTest) cmdCmpShow(ts *testscript.TestScript, _ bool, args []string) {\n\tcmdCmpShow(ts, args, func(_, name string) (string, error) {\n\t\tvar (\n\t\t\tstmts []string\n\t\t\tdb    = ts.Value(keyDB).(*sql.DB)\n\t\t)\n\t\trows, err := db.Query(\"SELECT sql FROM sqlite_schema where tbl_name = ?\", name)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"querying schema\")\n\t\t}\n\t\tdefer rows.Close()\n\t\tfor rows.Next() {\n\t\t\tvar s string\n\t\t\tif err := rows.Scan(&s); err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\tstmts = append(stmts, s)\n\t\t}\n\t\treturn strings.Join(stmts, \"\\n\"), nil\n\t})\n}\n\nfunc cmdCmpShow(ts *testscript.TestScript, args []string, show func(schema, name string) (string, error)) {\n\tif len(args) < 2 {\n\t\tts.Fatalf(\"invalid number of args to 'cmpshow': %d\", len(args))\n\t}\n\tvar (\n\t\tver   = ts.Getenv(\"version\")\n\t\tfname = args[len(args)-1]\n\t\tstmts = make([]string, 0, len(args)-1)\n\t)\n\tfor _, name := range args[:len(args)-1] {\n\t\tcreate, err := show(ts.Getenv(\"db\"), name)\n\t\tif err != nil {\n\t\t\tts.Fatalf(\"show table %q: %v\", name, err)\n\t\t}\n\t\tstmts = append(stmts, create)\n\t}\n\n\t// Check if there is a file prefixed by database version (1.sql and <version>/1.sql).\n\tif _, err := os.Stat(ts.MkAbs(filepath.Join(ver, fname))); err == nil {\n\t\tfname = filepath.Join(ver, fname)\n\t}\n\tt1, t2 := strings.Join(stmts, \"\\n\"), ts.ReadFile(fname)\n\tif strings.TrimSpace(t1) == strings.TrimSpace(t2) {\n\t\treturn\n\t}\n\tvar sb strings.Builder\n\tts.Check(diff.Text(\"show\", fname, t1, t2, &sb))\n\tts.Fatalf(\"\\n%s\", sb.String())\n}\n\nfunc (t *myTest) cmdCmpHCL(ts *testscript.TestScript, _ bool, args []string) {\n\tr := strings.NewReplacer(\"$charset\", ts.Getenv(\"charset\"), \"$collate\", ts.Getenv(\"collate\"), \"$db\", ts.Getenv(\"db\"))\n\tcmdCmpHCL(ts, args, func(name string) (string, error) {\n\t\ts, err := ts.Value(\"drv\").(migrate.Driver).InspectSchema(context.Background(), name, nil)\n\t\tts.Check(err)\n\t\tbuf, err := mysql.MarshalHCL(s)\n\t\trequire.NoError(t, err)\n\t\treturn string(buf), nil\n\t}, func(s string) string {\n\t\treturn r.Replace(ts.ReadFile(s))\n\t})\n}\n\nfunc (t *pgTest) cmdCmpHCL(ts *testscript.TestScript, _ bool, args []string) {\n\tcmdCmpHCL(ts, args, func(name string) (string, error) {\n\t\ts, err := ts.Value(\"drv\").(migrate.Driver).InspectSchema(context.Background(), name, nil)\n\t\tts.Check(err)\n\t\tbuf, err := postgres.MarshalHCL(s)\n\t\trequire.NoError(t, err)\n\t\treturn string(buf), nil\n\t}, func(s string) string {\n\t\treturn strings.ReplaceAll(ts.ReadFile(s), \"$db\", ts.Getenv(\"db\"))\n\t})\n}\n\nfunc (t *liteTest) cmdCmpHCL(ts *testscript.TestScript, _ bool, args []string) {\n\tcmdCmpHCL(ts, args, func(name string) (string, error) {\n\t\ts, err := ts.Value(keyDrv).(migrate.Driver).InspectSchema(context.Background(), \"main\", nil)\n\t\tts.Check(err)\n\t\tbuf, err := sqlite.MarshalHCL(s)\n\t\trequire.NoError(t, err)\n\t\treturn string(buf), nil\n\t}, func(s string) string {\n\t\treturn strings.ReplaceAll(ts.ReadFile(s), \"$db\", ts.Getenv(\"db\"))\n\t})\n}\n\nfunc cmdCmpHCL(ts *testscript.TestScript, args []string, inspect func(schema string) (string, error), read ...func(string) string) {\n\tif len(args) != 1 {\n\t\tts.Fatalf(\"invalid number of args to 'cmpinspect': %d\", len(args))\n\t}\n\tif len(read) == 0 {\n\t\tread = append(read, ts.ReadFile)\n\t}\n\tvar (\n\t\tfname = args[0]\n\t\tver   = ts.Getenv(\"version\")\n\t)\n\tf1, err := inspect(ts.Getenv(\"db\"))\n\tif err != nil {\n\t\tts.Fatalf(\"inspect schema %q: %v\", ts.Getenv(\"db\"), err)\n\t}\n\t// Check if there is a file prefixed by database version (1.sql and <version>/1.sql).\n\tif _, err := os.Stat(ts.MkAbs(filepath.Join(ver, fname))); err == nil {\n\t\tfname = filepath.Join(ver, fname)\n\t}\n\tf2 := read[0](fname)\n\tif strings.TrimSpace(f1) == strings.TrimSpace(f2) {\n\t\treturn\n\t}\n\tvar sb strings.Builder\n\tts.Check(diff.Text(\"inspect\", fname, f1, f2, &sb))\n\tts.Fatalf(\"\\n%s\", sb.String())\n}\n\nfunc (t *myTest) cmdExec(ts *testscript.TestScript, _ bool, args []string) {\n\tcmdExec(ts, args, t.db)\n}\n\nfunc (t *pgTest) cmdExec(ts *testscript.TestScript, _ bool, args []string) {\n\tcmdExec(ts, args, t.db)\n}\n\nfunc (t *liteTest) cmdExec(ts *testscript.TestScript, _ bool, args []string) {\n\tcmdExec(ts, args, ts.Value(keyDB).(*sql.DB))\n}\n\nfunc (t *myTest) cmdCLI(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdCLI(ts, neg, args, t.url(ts.Getenv(\"db\")), t.url(ts.Getenv(\"dev\")), ts.Getenv(atlasPathKey))\n}\n\nfunc (t *pgTest) cmdCLI(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdCLI(ts, neg, args, t.url(ts.Getenv(\"db\")), t.url(ts.Getenv(\"dev\")), ts.Getenv(atlasPathKey))\n}\n\nfunc (t *liteTest) cmdCLI(ts *testscript.TestScript, neg bool, args []string) {\n\tdbURL := fmt.Sprintf(\"sqlite://file:%s/atlas.sqlite?cache=shared&_fk=1\", ts.Getenv(\"WORK\"))\n\tcmdCLI(ts, neg, args, dbURL, \"sqlite://dev?mode=memory\", ts.Getenv(atlasPathKey))\n}\n\nfunc cmdCLI(ts *testscript.TestScript, neg bool, args []string, dbURL, devURL, cliPath string, envs ...string) {\n\tvar (\n\t\tworkDir = ts.Getenv(\"WORK\")\n\t\tr       = strings.NewReplacer(\"URL\", dbURL, \"DEV_URL\", devURL, \"$db\", ts.Getenv(\"db\"))\n\t)\n\tfor i, arg := range args {\n\t\targs[i] = r.Replace(arg)\n\t}\n\t// Whenever a migrate diff/apply command is executed, increase the default lock\n\t// timeout to 30s, as the default (10s) for synchronizing all our tests.\n\tif len(args) > 1 && args[0] == \"migrate\" && (args[1] == \"diff\" || args[1] == \"apply\") && !slices.Contains(args, \"--lock-timeout\") {\n\t\targs = append(args, \"--lock-timeout\", \"30s\")\n\t}\n\tswitch l := len(args); {\n\t// If command was run with a unix redirect-like suffix.\n\tcase l > 1 && args[l-2] == \">\":\n\t\toutPath := filepath.Join(workDir, args[l-1])\n\t\tf, err := os.Create(outPath)\n\t\tts.Check(err)\n\t\tdefer f.Close()\n\t\tcmd := exec.Command(cliPath, args[0:l-2]...)\n\t\tcmd.Stdout = f\n\t\tstderr := &bytes.Buffer{}\n\t\tcmd.Stderr = stderr\n\t\tcmd.Dir = workDir\n\t\tcmd.Env = append(cmd.Env,\n\t\t\t\"HOME=\"+ts.Getenv(\"HOME\"),\n\t\t\t\"PATH=\"+ts.Getenv(\"PATH\"),\n\t\t\t\"DOCKER_HOST=\"+ts.Getenv(\"DOCKER_HOST\"),\n\t\t)\n\t\tfor _, env := range envs {\n\t\t\tcmd.Env = append(cmd.Env, fmt.Sprintf(\"%s=%s\", env, ts.Getenv(env)))\n\t\t}\n\t\tif err := cmd.Run(); err != nil && !neg {\n\t\t\tts.Fatalf(\"\\n[stderr]\\n%s\", stderr)\n\t\t}\n\tdefault:\n\t\terr := ts.Exec(cliPath, args...)\n\t\tif !neg {\n\t\t\tts.Check(err)\n\t\t}\n\t\tif neg && err == nil {\n\t\t\tts.Fatalf(\"expected fail\")\n\t\t}\n\t}\n}\n\nfunc (t *myTest) cmdCmpMig(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdCmpMig(ts, neg, args)\n}\n\nfunc (t *pgTest) cmdCmpMig(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdCmpMig(ts, neg, args)\n}\n\nfunc (t *liteTest) cmdCmpMig(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdCmpMig(ts, neg, args)\n}\n\nvar reLiquibaseChangeset = regexp.MustCompile(\"--changeset atlas:[0-9]+-[0-9]+\")\n\n// cmdCmpMig compares a migration file under migrations with a provided file.\n// If the first argument is a filename that does exist, that file is used for comparison.\n// If there is no file with that name, the argument is parsed to an integer n and the\n// nth sql file is used for comparison. Lexicographic order of\n// the files in the directory is used to access the file of interest.\nfunc cmdCmpMig(ts *testscript.TestScript, _ bool, args []string) {\n\tif len(args) < 2 {\n\t\tts.Fatalf(\"invalid number of args to 'cmpmig': %d\", len(args))\n\t}\n\t// Check if there is a file prefixed by database version (1.sql and <version>/1.sql).\n\tvar (\n\t\tver   = ts.Getenv(\"version\")\n\t\tfname = args[1]\n\t)\n\tif _, err := os.Stat(ts.MkAbs(filepath.Join(ver, fname))); err == nil {\n\t\tfname = filepath.Join(ver, fname)\n\t}\n\texpected := strings.TrimSpace(ts.ReadFile(fname))\n\tdir, err := os.ReadDir(ts.MkAbs(\"migrations\"))\n\tts.Check(err)\n\tidx, err := strconv.Atoi(args[0])\n\tts.Check(err)\n\tcurrent := 0\n\tfor _, f := range dir {\n\t\tif f.IsDir() || !strings.HasSuffix(f.Name(), \".sql\") {\n\t\t\tcontinue\n\t\t}\n\t\tif current == idx {\n\t\t\tactual := strings.TrimSpace(ts.ReadFile(filepath.Join(\"migrations\", f.Name())))\n\t\t\texLines, acLines := strings.Split(actual, \"\\n\"), strings.Split(expected, \"\\n\")\n\t\t\tif len(exLines) != len(acLines) {\n\t\t\t\tvar sb strings.Builder\n\t\t\t\tts.Check(diff.Text(f.Name(), args[1], actual, expected, &sb))\n\t\t\t\tts.Fatalf(\"\\n%s\", sb.String())\n\t\t\t}\n\t\t\tfor i := range exLines {\n\t\t\t\t// Skip liquibase changeset comments since they contain a timestamp.\n\t\t\t\tif reLiquibaseChangeset.MatchString(acLines[i]) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif exLines[i] != acLines[i] {\n\t\t\t\t\tvar sb strings.Builder\n\t\t\t\t\tts.Check(diff.Text(f.Name(), args[1], actual, expected, &sb))\n\t\t\t\t\tts.Fatalf(\"\\n%s\", sb.String())\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tcurrent++\n\t}\n\tts.Fatalf(\"could not find the #%d migration\", idx)\n}\n\nfunc cmdExec(ts *testscript.TestScript, args []string, db *sql.DB) {\n\tif len(args) == 0 {\n\t\tts.Fatalf(\"missing statements for 'execsql'\")\n\t}\n\tfor i := range args {\n\t\ts := strings.ReplaceAll(args[i], \"$db\", ts.Getenv(\"db\"))\n\t\t_, err := db.Exec(s)\n\t\tts.Check(err)\n\t}\n}\n\nfunc (t *myTest) cmdExist(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdExist(ts, neg, args, func(schema, name string) (bool, error) {\n\t\tvar b bool\n\t\tif err := t.db.QueryRow(\"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?\", schema, name).Scan(&b); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\treturn b, nil\n\t})\n}\n\nfunc (t *pgTest) cmdExist(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdExist(ts, neg, args, func(schema, name string) (bool, error) {\n\t\tvar b bool\n\t\tif err := t.db.QueryRow(\"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = $1 AND TABLE_NAME = $2\", schema, name).Scan(&b); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\treturn b, nil\n\t})\n}\n\nfunc (t *liteTest) cmdExist(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdExist(ts, neg, args, func(_, name string) (bool, error) {\n\t\tvar (\n\t\t\tb  bool\n\t\t\tdb = ts.Value(keyDB).(*sql.DB)\n\t\t)\n\t\tif err := db.QueryRow(\"SELECT COUNT(*) FROM sqlite_master WHERE `type`='table' AND `name` = ?\", name).Scan(&b); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\treturn b, nil\n\t})\n}\n\nfunc cmdExist(ts *testscript.TestScript, neg bool, args []string, exists func(schema, name string) (bool, error)) {\n\tfor _, name := range args {\n\t\tb, err := exists(ts.Getenv(\"db\"), name)\n\t\tif err != nil {\n\t\t\tts.Fatalf(\"failed query table existence %q: %v\", name, err)\n\t\t}\n\t\tif !b != neg {\n\t\t\tts.Fatalf(\"table %q existence failed\", name)\n\t\t}\n\t}\n}\n\nfunc (t *myTest) cmdSynced(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdSynced(ts, neg, args, t.hclDiff)\n}\n\nfunc (t *myTest) cmdApply(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdApply(ts, neg, args, ts.Value(\"drv\").(migrate.Driver).ApplyChanges, t.hclDiff)\n}\n\nfunc (t *myTest) hclDiff(ts *testscript.TestScript, name string) ([]schema.Change, error) {\n\tvar (\n\t\tdesired = &schema.Schema{}\n\t\tf       = ts.ReadFile(name)\n\t\tctx     = context.Background()\n\t\tdrv     = ts.Value(\"drv\").(migrate.Driver)\n\t\tr       = strings.NewReplacer(\"$charset\", ts.Getenv(\"charset\"), \"$collate\", ts.Getenv(\"collate\"), \"$db\", ts.Getenv(\"db\"))\n\t)\n\tts.Check(mysql.EvalHCLBytes([]byte(r.Replace(f)), desired, nil))\n\tcurrent, err := drv.InspectSchema(ctx, desired.Name, nil)\n\tts.Check(err)\n\tdesired, err = ts.Value(\"dev\").(schema.Normalizer).NormalizeSchema(ctx, desired)\n\t// Normalization and diffing errors should\n\t// be returned to the caller.\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tchanges, err := drv.SchemaDiff(current, desired)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn changes, nil\n}\n\nfunc (t *pgTest) cmdSynced(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdSynced(ts, neg, args, t.hclDiff)\n}\n\nfunc (t *pgTest) cmdApply(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdApply(ts, neg, args, ts.Value(\"drv\").(migrate.Driver).ApplyChanges, t.hclDiff)\n}\n\nfunc (t *pgTest) hclDiff(ts *testscript.TestScript, name string) ([]schema.Change, error) {\n\tvar (\n\t\tdesired = &schema.Schema{}\n\t\tctx     = context.Background()\n\t\tdrv     = ts.Value(\"drv\").(migrate.Driver)\n\t\tf       = strings.ReplaceAll(ts.ReadFile(name), \"$db\", ts.Getenv(\"db\"))\n\t)\n\tts.Check(postgres.EvalHCLBytes([]byte(f), desired, nil))\n\tcurrent, err := drv.InspectSchema(ctx, desired.Name, nil)\n\tts.Check(err)\n\tdesired, err = ts.Value(\"dev\").(schema.Normalizer).NormalizeSchema(ctx, desired)\n\t// Normalization and diffing errors should\n\t// be returned to the caller.\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tchanges, err := drv.SchemaDiff(current, desired)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn changes, nil\n}\n\nfunc (t *liteTest) cmdSynced(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdSynced(ts, neg, args, t.hclDiff)\n}\n\nfunc (t *liteTest) cmdApply(ts *testscript.TestScript, neg bool, args []string) {\n\tcmdApply(ts, neg, args, ts.Value(keyDrv).(*sqlite.Driver).ApplyChanges, t.hclDiff)\n}\n\nfunc (t *liteTest) hclDiff(ts *testscript.TestScript, name string) ([]schema.Change, error) {\n\tvar (\n\t\tdesired = &schema.Schema{}\n\t\tf       = ts.ReadFile(name)\n\t\tdrv     = ts.Value(keyDrv).(*sqlite.Driver)\n\t)\n\tts.Check(sqlite.EvalHCLBytes([]byte(f), desired, nil))\n\tcurrent, err := drv.InspectSchema(context.Background(), desired.Name, nil)\n\tts.Check(err)\n\tchanges, err := drv.SchemaDiff(current, desired)\n\t// Diff errors should return to the caller.\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn changes, nil\n}\n\nfunc (t *myTest) clearSchema(ts *testscript.TestScript, _ bool, args []string) {\n\tif len(args) == 0 {\n\t\targs = append(args, ts.Getenv(\"db\"))\n\t}\n\t_, err := t.db.Exec(\"DROP DATABASE IF EXISTS \" + args[0])\n\tts.Check(err)\n\t_, err = t.db.Exec(\"CREATE DATABASE IF NOT EXISTS \" + args[0])\n\tts.Check(err)\n}\n\nfunc (t *pgTest) clearSchema(ts *testscript.TestScript, _ bool, args []string) {\n\tif len(args) == 0 {\n\t\targs = append(args, ts.Getenv(\"db\"))\n\t}\n\t_, err := t.db.Exec(fmt.Sprintf(\"DROP SCHEMA IF EXISTS %s CASCADE\", args[0]))\n\tts.Check(err)\n\t_, err = t.db.Exec(\"CREATE SCHEMA IF NOT EXISTS \" + args[0])\n\tts.Check(err)\n}\n\nfunc (t *liteTest) clearSchema(ts *testscript.TestScript, _ bool, _ []string) {\n\tfor _, stmt := range []string{\n\t\t\"PRAGMA writable_schema = 1;\",\n\t\t\"DELETE FROM sqlite_master WHERE type IN ('table', 'index', 'trigger');\",\n\t\t\"PRAGMA writable_schema = 0;\",\n\t\t\"VACUUM;\",\n\t} {\n\t\t_, err := ts.Value(keyDB).(*sql.DB).Exec(stmt)\n\t\tts.Check(err)\n\t}\n}\n\nfunc cmdSynced(ts *testscript.TestScript, neg bool, args []string, diff func(*testscript.TestScript, string) ([]schema.Change, error)) {\n\tif len(args) != 1 {\n\t\tts.Fatalf(\"unexpected number of args to synced command: %d\", len(args))\n\t}\n\tswitch changes, err := diff(ts, args[0]); {\n\tcase err != nil:\n\t\tts.Fatalf(\"unexpected diff failure on synced: %v\", err)\n\tcase len(changes) > 0 && !neg:\n\t\tts.Fatalf(\"expect no schema changes, but got: %d\", len(changes))\n\tcase len(changes) == 0 && neg:\n\t\tts.Fatalf(\"expect schema changes, but there are none\")\n\t}\n}\n\nfunc 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)) {\n\tchanges, err := diff(ts, args[0])\n\tswitch {\n\tcase err != nil && !neg:\n\t\tts.Fatalf(\"diff states: %v\", err)\n\t// If we expect to fail, and there's a specific error to compare.\n\tcase err != nil && len(args) == 2:\n\t\tmatchErr(ts, err, args[1])\n\t\treturn\n\t}\n\tswitch err := apply(context.Background(), changes); {\n\tcase err != nil && !neg:\n\t\tts.Fatalf(\"apply changes: %v\", err)\n\tcase err == nil && neg:\n\t\tts.Fatalf(\"unexpected apply success\")\n\t// If we expect to fail, and there's a specific error to compare.\n\tcase err != nil && len(args) == 2:\n\t\tmatchErr(ts, err, args[1])\n\t// Apply passed. Make sure there is no drift.\n\tcase !neg:\n\t\tchanges, err := diff(ts, args[0])\n\t\tts.Check(err)\n\t\tif len(changes) > 0 {\n\t\t\tts.Fatalf(\"unexpected schema changes: %d\", len(changes))\n\t\t}\n\t}\n}\n\nfunc matchErr(ts *testscript.TestScript, err error, p string) {\n\tre, rerr := regexp.Compile(`(?m)` + regexp.QuoteMeta(p))\n\tts.Check(rerr)\n\tif !re.MatchString(err.Error()) {\n\t\tts.Fatalf(\"mismatched errors: %v != %s\", err, p)\n\t}\n}\n\nfunc validJSON(ts *testscript.TestScript, _ bool, args []string) {\n\tts.Check(json.Unmarshal([]byte(ts.ReadFile(args[0])), new(map[string]any)))\n}\n"
  },
  {
    "path": "internal/integration/sqlite_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage integration\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"fmt\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/postgres\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlite\"\n\n\t_ \"github.com/mattn/go-sqlite3\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype liteTest struct {\n\t*testing.T\n\tdb   *sql.DB\n\tdrv  migrate.Driver\n\trrw  migrate.RevisionReadWriter\n\tfile string\n}\n\nfunc liteRun(t *testing.T, fn func(test *liteTest)) {\n\tt.Parallel()\n\tf := path.Join(t.TempDir(), strings.ReplaceAll(t.Name(), \"/\", \"_\"))\n\tdb, err := sql.Open(\"sqlite3\", fmt.Sprintf(\"file:%s?cache=shared&_fk=1\", f))\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, db.Close())\n\t})\n\tdrv, err := sqlite.Open(db)\n\trequire.NoError(t, err)\n\ttt := &liteTest{T: t, db: db, drv: drv, file: f, rrw: &rrw{}}\n\tfn(tt)\n}\n\nfunc TestSQLite_Executor(t *testing.T) {\n\tliteRun(t, func(t *liteTest) {\n\t\ttestExecutor(t)\n\t})\n}\n\nfunc TestSQLite_AddDropTable(t *testing.T) {\n\tliteRun(t, func(t *liteTest) {\n\t\ttestAddDrop(t)\n\t})\n}\n\nfunc TestSQLite_Relation(t *testing.T) {\n\tliteRun(t, func(t *liteTest) {\n\t\ttestRelation(t)\n\t})\n}\n\nfunc TestSQLite_ColumnCheck(t *testing.T) {\n\tliteRun(t, func(t *liteTest) {\n\t\tusersT := &schema.Table{\n\t\t\tName:  \"users\",\n\t\t\tAttrs: []schema.Attr{schema.NewCheck().SetName(\"users_c_check\").SetExpr(\"c > 5\")},\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t{Name: \"c\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t},\n\t\t}\n\t\tt.dropTables(usersT.Name)\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestSQLite_AddIndexedColumns(t *testing.T) {\n\tliteRun(t, func(t *liteTest) {\n\t\tusersT := &schema.Table{\n\t\t\tName:    \"users\",\n\t\t\tColumns: []*schema.Column{{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}}},\n\t\t}\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tt.dropTables(usersT.Name)\n\n\t\t// Insert 2 records to the users table, and make sure they are there\n\t\t// after executing migration.\n\t\t_, err := t.db.Exec(\"INSERT INTO users (id) VALUES (1), (2)\")\n\t\trequire.NoError(t, err)\n\n\t\tusersT.Columns = append(usersT.Columns, &schema.Column{\n\t\t\tName:    \"a\",\n\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Null: true},\n\t\t\tDefault: &schema.Literal{V: \"10\"},\n\t\t}, &schema.Column{\n\t\t\tName:    \"b\",\n\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Null: true},\n\t\t\tDefault: &schema.Literal{V: \"20\"},\n\t\t}, &schema.Column{\n\t\t\tName:    \"c\",\n\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Null: true},\n\t\t\tDefault: &schema.Literal{V: \"30\"},\n\t\t})\n\t\tusersT.Indexes = append(usersT.Indexes, &schema.Index{\n\t\t\tUnique: true,\n\t\t\tName:   \"id_a_b_c_unique\",\n\t\t\tParts:  []*schema.IndexPart{{C: usersT.Columns[0]}, {C: usersT.Columns[1]}, {C: usersT.Columns[2]}, {C: usersT.Columns[3]}},\n\t\t})\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 4, \"usersT contains 3 new columns and 1 new index\")\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\n\t\t// Scan records from the table to ensure correctness of\n\t\t// the rows transferring.\n\t\trows, err := t.db.Query(\"SELECT * FROM users\")\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, rows.Next())\n\t\tvar v [4]int\n\t\trequire.NoError(t, rows.Scan(&v[0], &v[1], &v[2], &v[3]))\n\t\trequire.Equal(t, [4]int{1, 10, 20, 30}, v)\n\t\trequire.True(t, rows.Next())\n\t\trequire.NoError(t, rows.Scan(&v[0], &v[1], &v[2], &v[3]))\n\t\trequire.Equal(t, [4]int{2, 10, 20, 30}, v)\n\t\trequire.False(t, rows.Next())\n\t\trequire.NoError(t, rows.Close())\n\n\t\t// Dropping a column from both table and index.\n\t\tusersT = t.loadUsers()\n\t\tidx, ok := usersT.Index(\"id_a_b_c_unique\")\n\t\trequire.True(t, ok)\n\t\trequire.Len(t, idx.Parts, 4)\n\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\tidx.Parts = idx.Parts[:len(idx.Parts)-1]\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 2)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, t.loadUsers())\n\n\t\t// Scan records from the table to ensure correctness of\n\t\t// the rows transferring.\n\t\trows, err = t.db.Query(\"SELECT * FROM users\")\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, rows.Next())\n\t\tvar u [3]int\n\t\trequire.NoError(t, rows.Scan(&u[0], &u[1], &u[2]))\n\t\trequire.Equal(t, [3]int{1, 10, 20}, u)\n\t\trequire.True(t, rows.Next())\n\t\trequire.NoError(t, rows.Scan(&u[0], &u[1], &u[2]))\n\t\trequire.Equal(t, [3]int{2, 10, 20}, u)\n\t\trequire.False(t, rows.Next())\n\t\trequire.NoError(t, rows.Close())\n\n\t})\n}\n\nfunc TestSQLite_AutoIncrement(t *testing.T) {\n\tliteRun(t, func(t *liteTest) {\n\t\tusersT := &schema.Table{\n\t\t\tName: \"users\",\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{sqlite.AutoIncrement{}}},\n\t\t\t},\n\t\t}\n\t\tusersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tt.dropTables(usersT.Name)\n\t\t_, err := t.db.Exec(\"INSERT INTO users DEFAULT VALUES\")\n\t\trequire.NoError(t, err)\n\t\tvar id int\n\t\terr = t.db.QueryRow(\"SELECT id FROM users\").Scan(&id)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, id)\n\t})\n}\n\nfunc TestSQLite_AutoIncrementSequence(t *testing.T) {\n\t// This test shows a bug detected in Ent when working with pre-defined auto-increment start values.\n\t// If there is a change somewhere to create an auto-increment with a start value, Atlas must make sure to create\n\t// an entry in the 'sqlite_sequence' table (and also ensure the table exists before attempting to create the entry).\n\tliteRun(t, func(t *liteTest) {\n\t\tt1 := &schema.Table{\n\t\t\tName: \"users\",\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{\n\t\t\t\t\tName:  \"id\",\n\t\t\t\t\tType:  &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}},\n\t\t\t\t\tAttrs: []schema.Attr{&sqlite.AutoIncrement{Seq: 10}},\n\t\t\t\t},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{&sqlite.AutoIncrement{}},\n\t\t}\n\t\tt1.PrimaryKey = &schema.Index{Table: t1, Parts: []*schema.IndexPart{{C: t1.Columns[0]}}}\n\t\tt1.Columns[0].Indexes = append(t1.Columns[0].Indexes, t1.PrimaryKey)\n\n\t\t// Planning the changes should not result in an error.\n\t\t_ = plan(t, \"col_seq\", &schema.AddTable{T: t1})\n\t})\n}\n\nfunc TestSQLite_AddColumns(t *testing.T) {\n\tliteRun(t, func(t *liteTest) {\n\t\tusersT := &schema.Table{\n\t\t\tName: \"users\",\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{sqlite.AutoIncrement{}}},\n\t\t\t},\n\t\t}\n\t\tusersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tt.dropTables(usersT.Name)\n\t\t_, err := t.db.Exec(\"INSERT INTO users (id) VALUES (1), (2)\")\n\t\trequire.NoError(t, err)\n\t\tusersT.Columns = append(\n\t\t\tusersT.Columns,\n\t\t\t&schema.Column{Name: \"null_int\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Null: true}},\n\t\t\t&schema.Column{Name: \"notnull_int\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}, Default: &schema.Literal{V: \"1\"}},\n\t\t\t&schema.Column{Name: \"null_real\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"real\"}, Null: true}},\n\t\t\t&schema.Column{Name: \"notnull_real\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"real\"}}, Default: &schema.Literal{V: \"1.0\"}},\n\t\t\t&schema.Column{Name: \"null_text\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Null: true}},\n\t\t\t&schema.Column{Name: \"notnull_text1\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}}, Default: &schema.Literal{V: \"hello\"}},\n\t\t\t&schema.Column{Name: \"notnull_text2\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}}, Default: &schema.Literal{V: \"'hello'\"}},\n\t\t\t&schema.Column{Name: \"null_blob\", Type: &schema.ColumnType{Type: &schema.BinaryType{T: \"blob\"}, Null: true}},\n\t\t\t&schema.Column{Name: \"notnull_blob\", Type: &schema.ColumnType{Type: &schema.BinaryType{T: \"blob\"}}, Default: &schema.Literal{V: \"'blob'\"}},\n\t\t)\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 9)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\n\t\t// Scan records from the table to ensure correctness of\n\t\t// the rows transferring.\n\t\trows, err := t.db.Query(\"SELECT id, notnull_int FROM users\")\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, rows.Next())\n\t\tvar v [2]int\n\t\trequire.NoError(t, rows.Scan(&v[0], &v[1]))\n\t\trequire.Equal(t, [2]int{1, 1}, v)\n\t\trequire.True(t, rows.Next())\n\t\trequire.NoError(t, rows.Scan(&v[0], &v[1]))\n\t\trequire.Equal(t, [2]int{2, 1}, v)\n\t\trequire.False(t, rows.Next())\n\t\trequire.NoError(t, rows.Close())\n\t})\n}\n\nfunc TestSQLite_ColumnInt(t *testing.T) {\n\tt.Run(\"ChangeTypeNull\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}}},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tusersT.Columns[0].Type.Null = true\n\t\t\tusersT.Columns[0].Type.Type = &schema.FloatType{T: \"real\"}\n\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 1)\n\t\t\trequire.Equal(t, schema.ChangeNull|schema.ChangeType, changes[0].(*schema.ModifyColumn).Change)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"ChangeDefault\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}, Default: &schema.Literal{V: \"1\"}}},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t\tfor _, x := range []string{\"2\", \"'3'\", \"10.1\"} {\n\t\t\t\tusersT.Columns[0].Default.(*schema.Literal).V = x\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t\t_, err := t.db.Exec(\"INSERT INTO users DEFAULT VALUES\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\trows, err := t.db.Query(\"SELECT a FROM users\")\n\t\t\trequire.NoError(t, err)\n\t\t\tfor _, e := range []driver.Value{2, 3, 10.1} {\n\t\t\t\tvar v driver.Value\n\t\t\t\trequire.True(t, rows.Next())\n\t\t\t\trequire.NoError(t, rows.Scan(&v))\n\t\t\t\trequire.EqualValues(t, e, v)\n\t\t\t}\n\t\t\trequire.False(t, rows.Next())\n\t\t\trequire.NoError(t, rows.Close())\n\t\t})\n\t})\n}\n\nfunc TestSQLite_ForeignKey(t *testing.T) {\n\tt.Run(\"ChangeAction\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\tusersT, postsT := t.users(), t.posts()\n\t\t\tt.dropTables(postsT.Name, usersT.Name)\n\t\t\tt.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})\n\t\t\tensureNoChange(t, postsT, usersT)\n\n\t\t\tpostsT = t.loadPosts()\n\t\t\t// The \"author_id\" constraint. SQLite does not support\n\t\t\t// getting the foreign-key constraint names at the moment.\n\t\t\tfk := postsT.ForeignKeys[0]\n\t\t\tfk.OnUpdate = schema.SetNull\n\t\t\tfk.OnDelete = schema.Cascade\n\t\t\tchanges := t.diff(t.loadPosts(), postsT)\n\t\t\trequire.Len(t, changes, 1)\n\t\t\tmodifyF, ok := changes[0].(*schema.ModifyForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)\n\n\t\t\tt.migrate(&schema.ModifyTable{T: postsT, Changes: changes})\n\t\t\tensureNoChange(t, postsT, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"UnsetNull\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\tusersT, postsT := t.users(), t.posts()\n\t\t\tt.dropTables(postsT.Name, usersT.Name)\n\t\t\tfk := postsT.ForeignKeys[0]\n\t\t\tfk.OnDelete = schema.SetNull\n\t\t\tfk.OnUpdate = schema.SetNull\n\t\t\tt.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})\n\t\t\tensureNoChange(t, postsT, usersT)\n\n\t\t\tpostsT = t.loadPosts()\n\t\t\tc, ok := postsT.Column(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tc.Type.Null = false\n\t\t\tfk = postsT.ForeignKeys[0]\n\t\t\tfk.OnUpdate = schema.NoAction\n\t\t\tfk.OnDelete = schema.NoAction\n\t\t\tchanges := t.diff(t.loadPosts(), postsT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\tmodifyC, ok := changes[0].(*schema.ModifyColumn)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyC.Change == schema.ChangeNull)\n\t\t\tmodifyF, ok := changes[1].(*schema.ModifyForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)\n\n\t\t\tt.migrate(&schema.ModifyTable{T: postsT, Changes: changes})\n\t\t\tensureNoChange(t, postsT, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"AddDrop\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\tusersT := t.users()\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tensureNoChange(t, usersT)\n\n\t\t\t// Add foreign key.\n\t\t\tusersT.Columns = append(usersT.Columns, &schema.Column{\n\t\t\t\tName: \"spouse_id\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\t})\n\t\t\tusersT.ForeignKeys = append(usersT.ForeignKeys, &schema.ForeignKey{\n\t\t\t\tSymbol:     \"spouse_id\",\n\t\t\t\tTable:      usersT,\n\t\t\t\tColumns:    usersT.Columns[len(usersT.Columns)-1:],\n\t\t\t\tRefTable:   usersT,\n\t\t\t\tRefColumns: usersT.Columns[:1],\n\t\t\t\tOnDelete:   schema.NoAction,\n\t\t\t})\n\n\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\taddC, ok := changes[0].(*schema.AddColumn)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, \"spouse_id\", addC.C.Name)\n\t\t\taddF, ok := changes[1].(*schema.AddForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, \"spouse_id\", addF.F.Symbol)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\n\t\t\t// Drop foreign keys.\n\t\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\t\tusersT.ForeignKeys = usersT.ForeignKeys[:len(usersT.ForeignKeys)-1]\n\t\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n}\n\nfunc TestSQLite_HCL(t *testing.T) {\n\tfull := `\nschema \"main\" {\n}\ntable \"users\" {\n\tschema = schema.main\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tprimary_key {\n\t\tcolumns = [table.users.column.id]\n\t}\n}\ntable \"posts\" {\n\tschema = schema.main\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tcolumn \"author_id\" {\n\t\ttype = int\n\t}\n\tforeign_key \"author\" {\n\t\tcolumns = [\n\t\t\ttable.posts.column.author_id,\n\t\t]\n\t\tref_columns = [\n\t\t\ttable.users.column.id,\n\t\t]\n\t}\n\tprimary_key {\n\t\tcolumns = [table.users.column.id]\n\t}\n}\n`\n\tempty := `\nschema \"main\" {\n}\n`\n\tliteRun(t, func(t *liteTest) {\n\t\ttestHCLIntegration(t, full, empty)\n\t})\n}\n\nfunc TestSQLite_DefaultsHCL(t *testing.T) {\n\tn := \"atlas_defaults\"\n\tliteRun(t, func(t *liteTest) {\n\t\tddl := `\ncreate table atlas_defaults\n(\n\tstring varchar(255) default \"hello_world\",\n\tquoted varchar(100) default 'never say \"never\"',\n\td date default current_timestamp,\n\tn integer default 0x100 \n)\n`\n\t\tt.dropTables(n)\n\t\t_, err := t.db.Exec(ddl)\n\t\trequire.NoError(t, err)\n\t\trealm := t.loadRealm()\n\t\tspec, err := sqlite.MarshalHCL(realm.Schemas[0])\n\t\trequire.NoError(t, err)\n\t\tvar s schema.Schema\n\t\terr = sqlite.EvalHCLBytes(spec, &s, nil)\n\t\trequire.NoError(t, err)\n\t\tt.dropTables(n)\n\t\tt.applyHcl(string(spec))\n\t\tensureNoChange(t, realm.Schemas[0].Tables[0])\n\t})\n}\n\nfunc TestSQLite_CLI(t *testing.T) {\n\th := `\n\t\t\tschema \"main\" {\n\t\t\t}\n\t\t\ttable \"users\" {\n\t\t\t\tschema = schema.main\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = int\n\t\t\t\t}\n\t\t\t}`\n\tt.Run(\"InspectFromEnv\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\tenv := fmt.Sprintf(`\nenv \"hello\" {\n\turl = \"%s\"\n\tsrc = \"./schema.hcl\"\n}\n`, t.url(\"\"))\n\t\t\twd, _ := os.Getwd()\n\t\t\tenvfile := filepath.Join(wd, \"atlas.hcl\")\n\t\t\terr := os.WriteFile(envfile, []byte(env), 0600)\n\t\t\tt.Cleanup(func() {\n\t\t\t\tos.Remove(envfile)\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestCLISchemaInspectEnv(t, h, \"hello\", sqlite.EvalHCL)\n\t\t})\n\t})\n\tt.Run(\"SchemaInspect\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\ttestCLISchemaInspect(t, h, t.url(\"\"), sqlite.EvalHCL)\n\t\t})\n\t})\n\tt.Run(\"SchemaApply\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\ttestCLISchemaApply(t, h, t.url(\"\"), \"--dev-url\", t.dev())\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyWithVars\", func(t *testing.T) {\n\t\th := `\nvariable \"tenant\" {\n\ttype = string\n}\nschema \"tenant\" {\n\tname = var.tenant\n}\ntable \"users\" {\n\tschema = schema.tenant\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n}\n`\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\ttestCLISchemaApply(t, h, t.url(\"\"), \"--var\", \"tenant=main\", \"--dev-url\", t.dev())\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyDryRun\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\ttestCLISchemaApplyDry(t, h, t.url(\"\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaDiffRun\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\ttestCLISchemaDiff(t, t.url(\"\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyAutoApprove\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\ttestCLISchemaApplyAutoApprove(t, h, t.url(\"\"))\n\t\t})\n\t})\n}\n\nfunc TestSQLite_Sanity(t *testing.T) {\n\tn := \"atlas_types_sanity\"\n\tddl := `\ncreate table atlas_types_sanity\n(\n    \"tInteger\"            integer(10)                     default 100                                   null,\n    \"tInt\"                int(10)                         default 100                                   null,\n    \"tTinyIny\"            tinyint(10)                     default 100                                   null,\n    \"tSmallInt\"           smallint(10)                    default 100                                   null,\n    \"tMediumInt\"          mediumint(10)                   default 100                                   null,\n    \"tIntegerBigInt\"      bigint(10)                      default 100                                   null,\n    \"tUnsignedBigInt\"     unsigned big int(10)            default 100                                   null,\n    \"tInt2\"               int2(10)                        default 100                                   null,\n    \"tInt8\"               int8(10)                        default 100                                   null,\n    \"tReal\"               real(10)                        default 100                                   null,\n    \"tDouble\"             double(10)                      default 100                                   null,\n    \"tDoublePrecision\"    double precision(10)            default 100                                   null,\n    \"tFloat\"              float(10)                       default 100                                   null,\n    \"tText\"               text(10)                        default 'I am Text'                       not null,\n    \"tCharacter\"          character(10)                   default 'I am Text'                       not null,\n    \"tVarchar\"            varchar(10)                     default 'I am Text'                       not null,\n    \"tVaryingCharacter\"   varying character(10)           default 'I am Text'                       not null,\n    \"tNchar\"              nchar(10)                       default 'I am Text'                       not null,\n    \"tNativeCharacter\"    native character(10)            default 'I am Text'                       not null,\n    \"tNVarChar\"           nvarchar(10)                    default 'I am Text'                       not null,\n    \"tClob\"               clob(10)                        default 'I am Text'                       not null,\n    \"tBlob\"               blob(10)                        default 'A'                               not null,\n    \"tNumeric\"            numeric(10)                     default 100                               not null,\n    \"tDecimal\"            decimal(10,5)                   default 100                               not null,\n    \"tBoolean\"            boolean                         default false                             not null,\n    \"tDate\"               date                            default 'now()'                           not null ,\n    \"tDatetime\"           datetime                        default 'now()'                           not null \n);\n`\n\tliteRun(t, func(t *liteTest) {\n\t\tt.dropTables(n)\n\t\t_, err := t.db.Exec(ddl)\n\t\trequire.NoError(t, err)\n\t\trealm := t.loadRealm()\n\t\trequire.Len(t, realm.Schemas, 1)\n\t\tts, ok := realm.Schemas[0].Table(n)\n\t\trequire.True(t, ok)\n\t\texpected := schema.Table{\n\t\t\tName:   n,\n\t\t\tSchema: realm.Schemas[0],\n\t\t\tAttrs:  ts.Attrs,\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{\n\t\t\t\t\tName: \"tInteger\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\", Unsigned: false}, Raw: \"integer(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tInt\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\", Unsigned: false}, Raw: \"int(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tTinyIny\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"tinyint\", Unsigned: false}, Raw: \"tinyint(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tSmallInt\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"smallint\", Unsigned: false}, Raw: \"smallint(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tMediumInt\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"mediumint\", Unsigned: false}, Raw: \"mediumint(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tIntegerBigInt\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\", Unsigned: false}, Raw: \"bigint(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tUnsignedBigInt\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"unsigned big int\", Unsigned: false}, Raw: \"unsigned big int(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tInt2\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int2\", Unsigned: false}, Raw: \"int2(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tInt8\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int8\", Unsigned: false}, Raw: \"int8(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tReal\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.FloatType{T: \"real\", Precision: 0}, Raw: \"real(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tDouble\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.FloatType{T: \"double\", Precision: 0}, Raw: \"double(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tDoublePrecision\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.FloatType{T: \"double precision\", Precision: 0}, Raw: \"double precision(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tFloat\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.FloatType{T: \"float\", Precision: 0}, Raw: \"float(10)\", Null: true},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tText\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"text\", Size: 10}, Raw: \"text(10)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'I am Text'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tCharacter\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"character\", Size: 10}, Raw: \"character(10)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'I am Text'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tVarchar\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"varchar\", Size: 10}, Raw: \"varchar(10)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'I am Text'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tVaryingCharacter\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"varying character\", Size: 10}, Raw: \"varying character(10)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'I am Text'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tNchar\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"nchar\", Size: 10}, Raw: \"nchar(10)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'I am Text'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tNativeCharacter\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"native character\", Size: 10}, Raw: \"native character(10)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'I am Text'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tNVarChar\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"nvarchar\", Size: 10}, Raw: \"nvarchar(10)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'I am Text'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tClob\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"clob\", Size: 10}, Raw: \"clob(10)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'I am Text'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tBlob\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"blob\"}, Raw: \"blob(10)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'A'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tNumeric\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 10}, Raw: \"numeric(10)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tDecimal\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\", Precision: 10, Scale: 5}, Raw: \"decimal(10,5)\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"100\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tBoolean\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}, Raw: \"boolean\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"false\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tDate\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"date\"}, Raw: \"date\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'now()'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tDatetime\",\n\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"datetime\"}, Raw: \"datetime\", Null: false},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"'now()'\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\trequire.EqualValues(t, &expected, ts)\n\t})\n\n\tt.Run(\"ImplicitIndexes\", func(t *testing.T) {\n\t\tliteRun(t, func(t *liteTest) {\n\t\t\ttestImplicitIndexes(t, t.db)\n\t\t})\n\t})\n}\n\nfunc (t *liteTest) driver() migrate.Driver {\n\treturn t.drv\n}\n\nfunc (t *liteTest) revisionsStorage() migrate.RevisionReadWriter {\n\treturn t.rrw\n}\n\nfunc (t *liteTest) dropSchemas(...string) {}\n\nfunc (t *liteTest) applyHcl(spec string) {\n\trealm := t.loadRealm()\n\tvar desired schema.Schema\n\terr := sqlite.EvalHCLBytes([]byte(spec), &desired, nil)\n\trequire.NoError(t, err)\n\texisting := realm.Schemas[0]\n\tdiff, err := t.drv.SchemaDiff(existing, &desired)\n\trequire.NoError(t, err)\n\terr = t.drv.ApplyChanges(context.Background(), diff)\n\trequire.NoError(t, err)\n}\n\nfunc (t *liteTest) loadRealm() *schema.Realm {\n\tr, err := t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\tSchemas: []string{\"main\"},\n\t\tMode:    schema.InspectSchemas | schema.InspectTables,\n\t})\n\trequire.NoError(t, err)\n\treturn r\n}\n\nfunc (t *liteTest) loadUsers() *schema.Table {\n\treturn t.loadTable(\"users\")\n}\n\nfunc (t *liteTest) loadPosts() *schema.Table {\n\treturn t.loadTable(\"posts\")\n}\n\nfunc (t *liteTest) loadTable(name string) *schema.Table {\n\trealm := t.loadRealm()\n\trequire.Len(t, realm.Schemas, 1)\n\ttable, ok := realm.Schemas[0].Table(name)\n\trequire.True(t, ok)\n\treturn table\n}\n\nfunc (t *liteTest) users() *schema.Table {\n\tusersT := &schema.Table{\n\t\tName:   \"users\",\n\t\tSchema: t.realm().Schemas[0],\n\t\tColumns: []*schema.Column{\n\t\t\t{\n\t\t\t\tName: \"id\",\n\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"x\",\n\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}},\n\t\t\t},\n\t\t},\n\t}\n\tusersT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: usersT.Columns[0]}}}\n\treturn usersT\n}\n\nfunc (t *liteTest) posts() *schema.Table {\n\tusersT := t.users()\n\tpostsT := &schema.Table{\n\t\tName:   \"posts\",\n\t\tSchema: t.realm().Schemas[0],\n\t\tColumns: []*schema.Column{\n\t\t\t{\n\t\t\t\tName:  \"id\",\n\t\t\t\tType:  &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t\tAttrs: []schema.Attr{&postgres.Identity{}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"author_id\",\n\t\t\t\tType:    &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Null: true},\n\t\t\t\tDefault: &schema.RawExpr{X: \"10\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"ctime\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"timestamp\", Type: &schema.TimeType{T: \"timestamp\"}},\n\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\tX: \"CURRENT_TIMESTAMP\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tAttrs: []schema.Attr{\n\t\t\t&schema.Comment{Text: \"posts comment\"},\n\t\t},\n\t}\n\tpostsT.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: postsT.Columns[0]}}}\n\tpostsT.Indexes = []*schema.Index{\n\t\t{Name: \"author_id\", Parts: []*schema.IndexPart{{C: postsT.Columns[1]}}},\n\t\t{Name: \"id_author_id_unique\", Unique: true, Parts: []*schema.IndexPart{{C: postsT.Columns[1]}, {C: postsT.Columns[0]}}},\n\t}\n\tpostsT.ForeignKeys = []*schema.ForeignKey{\n\t\t{Symbol: \"author_id\", Table: postsT, Columns: postsT.Columns[1:2], RefTable: usersT, RefColumns: usersT.Columns[:1], OnDelete: schema.NoAction},\n\t}\n\treturn postsT\n}\n\nfunc (t *liteTest) realm() *schema.Realm {\n\tr := &schema.Realm{\n\t\tSchemas: []*schema.Schema{\n\t\t\t{\n\t\t\t\tName: \"main\",\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&sqlite.File{Name: t.file},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tr.Schemas[0].Realm = r\n\treturn r\n}\n\nfunc (t *liteTest) diff(t1, t2 *schema.Table) []schema.Change {\n\tchanges, err := t.drv.TableDiff(t1, t2)\n\trequire.NoError(t, err)\n\treturn changes\n}\n\nfunc (t *liteTest) migrate(changes ...schema.Change) {\n\terr := t.drv.ApplyChanges(context.Background(), changes)\n\trequire.NoError(t, err)\n}\n\nfunc (t *liteTest) dropTables(names ...string) {\n\tt.Cleanup(func() {\n\t\tfor i := range names {\n\t\t\t_, err := t.db.Exec(\"DROP TABLE IF EXISTS \" + names[i])\n\t\t\trequire.NoError(t.T, err, \"drop tables %q\", names[i])\n\t\t}\n\t})\n}\n\nfunc (t *liteTest) url(_ string) string {\n\treturn fmt.Sprintf(\"sqlite://file:%s?cache=shared&_fk=1\", t.file)\n}\n\nfunc (t *liteTest) dev() string {\n\treturn fmt.Sprintf(\"sqlite://%s?mode=memory&_fk=1\", t.Name())\n}\n\nfunc (t *liteTest) applyRealmHcl(spec string) {\n\tt.applyHcl(spec)\n}\n"
  },
  {
    "path": "internal/integration/testdata/migrations/mysql/1_initial.sql",
    "content": "CREATE SCHEMA IF NOT EXISTS `bc_test`;\nCREATE TABLE `bc_test`.`bc_tbl` (`col` INTEGER NULL);"
  },
  {
    "path": "internal/integration/testdata/migrations/mysql/atlas.sum",
    "content": "h1:FT0VjrL64KJmuOe1Dq4dpbG/50Kwn0lZqfopa6BhJM8=\n1_initial.sql h1:bWUYLjb0oiGQHf45Q08aKFKxVZ3pZBArJnSmuGBw9X4=\n"
  },
  {
    "path": "internal/integration/testdata/migrations/mysqlock/1.sql",
    "content": "CREATE TABLE `t1` (`id` int);\nCREATE TABLE `t2` (`id` int);\nselect sleep(0.1);\nCREATE TABLE `t3` (`id` int);\nCREATE TABLE `t4` (`id` int);\nCREATE TABLE `t5` (`id` int);\nselect sleep(0.1);\nCREATE TABLE `t6` (`id` int);\n"
  },
  {
    "path": "internal/integration/testdata/migrations/mysqlock/2.sql",
    "content": "ALTER TABLE `t1` ADD COLUMN `c1` varchar(255) DEFAULT 'name';\nALTER TABLE `t2` ADD COLUMN `c1` varchar(255) DEFAULT 'name';\nselect sleep(0.1);\nALTER TABLE `t3` ADD COLUMN `c1` varchar(255) DEFAULT 'name';\nALTER TABLE `t4` ADD COLUMN `c1` varchar(255) DEFAULT 'name';\nselect sleep(0.1);\nALTER TABLE `t5` ADD COLUMN `c1` varchar(255) DEFAULT 'name';\nALTER TABLE `t6` ADD COLUMN `c1` varchar(255) DEFAULT 'name';\nALTER TABLE `t1` ADD COLUMN `c2` varchar(255) DEFAULT 'name';\nALTER TABLE `t2` ADD COLUMN `c2` varchar(255) DEFAULT 'name';\nselect sleep(0.1);\nALTER TABLE `t3` ADD COLUMN `c2` varchar(255) DEFAULT 'name';\nALTER TABLE `t4` ADD COLUMN `c2` varchar(255) DEFAULT 'name';\nselect sleep(0.1);           \nALTER TABLE `t5` ADD COLUMN `c2` varchar(255) DEFAULT 'name';\nALTER TABLE `t6` ADD COLUMN `c2` varchar(255) DEFAULT 'name';\n"
  },
  {
    "path": "internal/integration/testdata/migrations/mysqlock/3.sql",
    "content": "CREATE TABLE `t7` (`id` int);\nselect sleep(0.1);\nCREATE TABLE `t8` (`id` int);\nCREATE TABLE `t9` (`id` int);\n"
  },
  {
    "path": "internal/integration/testdata/migrations/mysqlock/atlas.sum",
    "content": "h1:XiFkhbkD+gUR/ry9+AVfyLW4X/tYaVUHFul5q0Kvtpo=\n1.sql h1:+HoZslM3E59DllQlUXd5TFnPw+9de9IBNQEYdn77f7c=\n2.sql h1:OliSiXPsLoVoWixWDC/yBJUtjrxnMMm+hjCf2Sz66Rk=\n3.sql h1:Gb5M9ibe0COwTBrb08v/4VuWXxJ55+D2lSLXHLVa/Po=\n"
  },
  {
    "path": "internal/integration/testdata/migrations/postgres/1_initial.sql",
    "content": "CREATE SCHEMA IF NOT EXISTS \"bc_test\";\nCREATE TABLE \"bc_test\".\"bc_tbl\" (\"col\" INTEGER NULL);"
  },
  {
    "path": "internal/integration/testdata/migrations/postgres/atlas.sum",
    "content": "h1:80V3wCzovMg2ot2hR0arbEjEfMfKWDeQNrXZJbFPF10=\n1_initial.sql h1:53poyM34ShPWCVU41ldi4d9LUrzqPiQfBdEq//yH4Jo=\n"
  },
  {
    "path": "internal/integration/testdata/mysql/autoincrement.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\n# Setup a custom AUTO_INCREMENT initial value.\napply 2.hcl\ncmpshow users 2.sql\n\n# Increase the AUTO_INCREMENT value.\napply 3.hcl\ncmpshow users 3.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"id\" {\n    null = false\n    type = bigint\n    auto_increment = true\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  PRIMARY KEY (`id`)\n)\n\n-- mysql8/1.sql --\nCREATE TABLE `users` (\n  `id` bigint NOT NULL AUTO_INCREMENT,\n  PRIMARY KEY (`id`)\n)\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"id\" {\n    null = false\n    type = bigint\n    auto_increment = true\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n  auto_increment = 1000\n}\n\n-- 2.sql --\nCREATE TABLE `users` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  PRIMARY KEY (`id`)\n) AUTO_INCREMENT=1000\n\n-- mysql8/2.sql --\nCREATE TABLE `users` (\n  `id` bigint NOT NULL AUTO_INCREMENT,\n  PRIMARY KEY (`id`)\n) AUTO_INCREMENT=1000\n\n-- 3.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"id\" {\n    null = false\n    type = bigint\n    auto_increment = true\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n  auto_increment = 2000\n}\n\n-- 3.sql --\nCREATE TABLE `users` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  PRIMARY KEY (`id`)\n) AUTO_INCREMENT=2000\n\n-- mysql8/3.sql --\nCREATE TABLE `users` (\n  `id` bigint NOT NULL AUTO_INCREMENT,\n  PRIMARY KEY (`id`)\n) AUTO_INCREMENT=2000"
  },
  {
    "path": "internal/integration/testdata/mysql/check-maria.txtar",
    "content": "only maria107\n\natlas schema inspect --url file://schema.sql --dev-url URL > got.hcl\ncmp expected.hcl got.hcl\n\natlas schema inspect --url file://schema.sql --dev-url URL --format '{{ sql . \"  \" }}' > got.sql\ncmp expected.sql got.sql\n\n-- schema.sql --\nCREATE TABLE t1(\n  buf json,\n  name varchar(20) CHECK(name in ('a', 'b', 'c')),\n  age int CHECK(age > 0),\n  -- MariaDB check constraint names are not unique.\n  CONSTRAINT `check1` CHECK (name <> 'a' or age > 10)\n);\n\nCREATE TABLE t2(\n  buf json,\n  name varchar(20) CHECK(name in ('a', 'b', 'c')),\n  age int CHECK(age > 1),\n  -- MariaDB check constraint names are not unique.\n  CONSTRAINT `check1` CHECK (name <> 'a' or age > 10)\n);\n\n-- expected.hcl --\ntable \"t1\" {\n  schema = schema.script_check_maria\n  column \"buf\" {\n    null = true\n    type = json\n  }\n  column \"name\" {\n    null = true\n    type = varchar(20)\n  }\n  column \"age\" {\n    null = true\n    type = int\n  }\n  check \"age\" {\n    expr = \"`age` > 0\"\n  }\n  check \"check1\" {\n    expr = \"`name` <> 'a' or `age` > 10\"\n  }\n  check \"name\" {\n    expr = \"`name` in ('a','b','c')\"\n  }\n}\ntable \"t2\" {\n  schema = schema.script_check_maria\n  column \"buf\" {\n    null = true\n    type = json\n  }\n  column \"name\" {\n    null = true\n    type = varchar(20)\n  }\n  column \"age\" {\n    null = true\n    type = int\n  }\n  check \"age\" {\n    expr = \"`age` > 1\"\n  }\n  check \"check1\" {\n    expr = \"`name` <> 'a' or `age` > 10\"\n  }\n  check \"name\" {\n    expr = \"`name` in ('a','b','c')\"\n  }\n}\nschema \"script_check_maria\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}\n-- expected.sql --\n-- Create \"t1\" table\nCREATE TABLE `t1` (\n  `buf` json NULL,\n  `name` varchar(20) NULL,\n  `age` int NULL,\n  CONSTRAINT `age` CHECK (`age` > 0),\n  CONSTRAINT `check1` CHECK (`name` <> 'a' or `age` > 10),\n  CONSTRAINT `name` CHECK (`name` in ('a','b','c'))\n) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\n-- Create \"t2\" table\nCREATE TABLE `t2` (\n  `buf` json NULL,\n  `name` varchar(20) NULL,\n  `age` int NULL,\n  CONSTRAINT `age` CHECK (`age` > 1),\n  CONSTRAINT `check1` CHECK (`name` <> 'a' or `age` > 10),\n  CONSTRAINT `name` CHECK (`name` in ('a','b','c'))\n) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;"
  },
  {
    "path": "internal/integration/testdata/mysql/check.txtar",
    "content": "only mysql8\n\natlas schema inspect --url file://schema.sql --dev-url URL > got.hcl\ncmp expected.hcl got.hcl\n\natlas schema inspect --url file://schema.sql --dev-url URL --format '{{ sql . \"  \" }}' > got.sql\ncmp expected.sql got.sql\n\natlas migrate diff v1 --to file://schema.sql --dev-url URL --format '{{ sql . \"  \" }}'\ncmpmig 0 migration.v1.sql\natlas migrate diff v1-check --to file://schema.sql --dev-url URL --format '{{ sql . \"  \" }}'\nstdout 'The migration directory is synced with the desired state, no changes to be made'\n\natlas migrate diff v2 --to file://schema.v2.sql --dev-url URL --format '{{ sql . \"  \" }}'\ncmpmig 1 migration.v2.sql\natlas migrate diff v2-check --to file://schema.v2.sql --dev-url URL --format '{{ sql . \"  \" }}'\nstdout 'The migration directory is synced with the desired state, no changes to be made'\n\natlas migrate diff v3 --to file://schema.v3.sql --dev-url URL --format '{{ sql . \"  \" }}'\ncmpmig 2 migration.v3.sql\natlas migrate diff v3 --to file://schema.v3.sql --dev-url URL --format '{{ sql . \"  \" }}'\nstdout 'The migration directory is synced with the desired state, no changes to be made'\n\n-- schema.sql --\nCREATE TABLE t1(\n  name varchar(20) CHECK(name in ('a', 'b', 'c')),\n  age int CHECK(age > 0),\n  -- MySQL check constraint names are unique in schema level.\n  CONSTRAINT `t1_check` CHECK (name <> 'a' or age > 10)\n);\n\nCREATE TABLE t2(\n  name varchar(20) CHECK(name in ('a', 'b', 'c')),\n  age int CHECK(age > 0),\n  -- MySQL check constraint names are unique in schema level.\n  CONSTRAINT `t2_check` CHECK (name <> 'a' or age > 10)\n);\n\n-- expected.hcl --\ntable \"t1\" {\n  schema = schema.script_check\n  column \"name\" {\n    null = true\n    type = varchar(20)\n  }\n  column \"age\" {\n    null = true\n    type = int\n  }\n  check \"t1_check\" {\n    expr = \"((`name` <> _utf8mb4'a') or (`age` > 10))\"\n  }\n  check \"t1_chk_1\" {\n    expr = \"(`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c'))\"\n  }\n  check \"t1_chk_2\" {\n    expr = \"(`age` > 0)\"\n  }\n}\ntable \"t2\" {\n  schema = schema.script_check\n  column \"name\" {\n    null = true\n    type = varchar(20)\n  }\n  column \"age\" {\n    null = true\n    type = int\n  }\n  check \"t2_check\" {\n    expr = \"((`name` <> _utf8mb4'a') or (`age` > 10))\"\n  }\n  check \"t2_chk_1\" {\n    expr = \"(`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c'))\"\n  }\n  check \"t2_chk_2\" {\n    expr = \"(`age` > 0)\"\n  }\n}\nschema \"script_check\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_0900_ai_ci\"\n}\n-- expected.sql --\n-- Create \"t1\" table\nCREATE TABLE `t1` (\n  `name` varchar(20) NULL,\n  `age` int NULL,\n  CONSTRAINT `t1_check` CHECK ((`name` <> _utf8mb4'a') or (`age` > 10)),\n  CONSTRAINT `t1_chk_1` CHECK (`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c')),\n  CONSTRAINT `t1_chk_2` CHECK (`age` > 0)\n) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;\n-- Create \"t2\" table\nCREATE TABLE `t2` (\n  `name` varchar(20) NULL,\n  `age` int NULL,\n  CONSTRAINT `t2_check` CHECK ((`name` <> _utf8mb4'a') or (`age` > 10)),\n  CONSTRAINT `t2_chk_1` CHECK (`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c')),\n  CONSTRAINT `t2_chk_2` CHECK (`age` > 0)\n) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;\n-- migration.v1.sql --\n-- Create \"t1\" table\nCREATE TABLE `t1` (\n  `name` varchar(20) NULL,\n  `age` int NULL,\n  CONSTRAINT `t1_check` CHECK ((`name` <> _utf8mb4'a') or (`age` > 10)),\n  CONSTRAINT `t1_chk_1` CHECK (`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c')),\n  CONSTRAINT `t1_chk_2` CHECK (`age` > 0)\n) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;\n-- Create \"t2\" table\nCREATE TABLE `t2` (\n  `name` varchar(20) NULL,\n  `age` int NULL,\n  CONSTRAINT `t2_check` CHECK ((`name` <> _utf8mb4'a') or (`age` > 10)),\n  CONSTRAINT `t2_chk_1` CHECK (`name` in (_utf8mb4'a',_utf8mb4'b',_utf8mb4'c')),\n  CONSTRAINT `t2_chk_2` CHECK (`age` > 0)\n) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;\n-- schema.v2.sql --\nCREATE TABLE t1(\n  name varchar(20) CHECK(name in ('a', 'b', 'c')),\n  age int CHECK(age > 0),\n  -- MySQL check constraint names are unique in schema level.\n  CONSTRAINT `t1_check` CHECK (name <> 'b' or age > 10)\n);\nCREATE TABLE t2(\n  name varchar(20) CHECK(name in ('a', 'b', 'c')),\n  age int CHECK(age > 0),\n  -- MySQL check constraint names are unique in schema level.\n  CONSTRAINT `t2_check` CHECK (name <> 'a' or age > 10)\n);\n-- migration.v2.sql --\n-- Modify \"t1\" table\nALTER TABLE `t1` DROP CHECK `t1_check`, ADD CONSTRAINT `t1_check` CHECK ((`name` <> _utf8mb4'b') or (`age` > 10));\n-- schema.v3.sql --\nCREATE TABLE t1(\n  name varchar(20) CHECK(name in ('a', 'b', 'c')),\n  age int CHECK(age > 0),\n  -- MySQL check constraint names are unique in schema level.\n  CONSTRAINT `t1_check` CHECK (name <> 'b' or age > 10)\n);\nCREATE TABLE t2(\n  name varchar(20) CHECK(name in ('a', 'b', 'c')),\n  age int CHECK(age > 0),\n  -- MySQL check constraint names are unique in schema level.\n  CONSTRAINT `t2_check` CHECK (name <> 'b' or age > 10)\n);\n-- migration.v3.sql --\n-- Modify \"t2\" table\nALTER TABLE `t2` DROP CHECK `t2_check`, ADD CONSTRAINT `t2_check` CHECK ((`name` <> _utf8mb4'b') or (`age` > 10));"
  },
  {
    "path": "internal/integration/testdata/mysql/cli-inspect-file.txtar",
    "content": "only mysql8\n\n# inspect without dev-db will failed\n! atlas schema inspect -u file://a.sql\nstderr 'Error: --dev-url cannot be empty'\n\n# inspect file to HCL\natlas schema inspect -u file://a.sql --dev-url URL > inspected.hcl\ncmp inspected.hcl script_cli_inspect.hcl\n\n# inspect file to SQL\natlas schema inspect -u file://a.sql --dev-url URL --format '{{ sql . }}' > inspected.sql\ncmp inspected.sql script_cli_inspect.sql\n\n-- a.sql --\ncreate table users (\n  id int NOT NULL,\n  PRIMARY KEY (id)\n)\n\n-- script_cli_inspect.hcl --\ntable \"users\" {\n  schema = schema.script_cli_inspect_file\n  column \"id\" {\n    null = false\n    type = int\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\nschema \"script_cli_inspect_file\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_0900_ai_ci\"\n}\n-- script_cli_inspect.sql --\n-- Create \"users\" table\nCREATE TABLE `users` (`id` int NOT NULL, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;\n"
  },
  {
    "path": "internal/integration/testdata/mysql/cli-migrate-apply-datasrc.txtar",
    "content": "only mysql8\n\natlas migrate hash\natlas migrate apply --url URL --env dev --var \"url=URL\" --var \"pattern=script_cli_migrate_apply_datasrc\"\nstdout 'Migrating to version 1 \\(1 migrations in total\\):'\n\n-- atlas.hcl --\nvariable \"url\" {\n  type = string\n}\n\nvariable \"pattern\" {\n  type = string\n}\n\ndata \"sql\" \"tenants\" {\n  url = var.url\n  query = <<EOS\nSELECT `schema_name`\n  FROM `information_schema`.`schemata`\n  WHERE `schema_name` LIKE ?\nEOS\n  args = [var.pattern]\n}\n\nenv \"dev\" {\n  for_each = toset(data.sql.tenants.values)\n  url      = urlsetpath(var.url, each.value)\n}\n\n-- migrations/1_create_users.sql --\nCREATE TABLE `users` (\n  `id` bigint NOT NULL AUTO_INCREMENT,\n  PRIMARY KEY (`id`)\n)\n\n"
  },
  {
    "path": "internal/integration/testdata/mysql/cli-migrate-apply.txtar",
    "content": "only mysql\n\n! atlas migrate apply\nstderr 'Error: checksum file not found'\nstdout 'You have a checksum error in your migration directory.'\nstdout 'atlas migrate hash'\n\natlas migrate hash\n\n# Apply all of them\natlas migrate apply --url URL --revisions-schema $db\nstdout 'Migrating to version 3 \\(3 migrations in total\\):'\nstdout '-- migrating version 1'\nstdout '-> 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;'\nstdout '-- migrating version 2'\nstdout '-> ALTER TABLE `users` ADD UNIQUE INDEX `age` \\(`age`\\);'\nstdout '-- migrating version 3'\nstdout '-> CREATE TABLE `pets` \\(`id` bigint NOT NULL AUTO_INCREMENT, `name` varchar\\(255\\) NOT NULL, PRIMARY KEY \\(`id`\\)\\) CHARSET utf8mb4 COLLATE utf8mb4_bin;'\nstdout '-- 3 migrations'\nstdout '-- 3 sql statements'\ncmpshow users users.sql\ncmpshow pets pets.sql\n\natlas migrate apply --url URL --revisions-schema $db\nstdout 'No migration files to execute'\n\nclearSchema\n\n# Apply one by one\natlas migrate apply --url URL --revisions-schema $db 1\nstdout 'Migrating to version 1 \\(1 migrations in total\\):'\ncmpshow users users_1.sql\n\natlas migrate apply --url URL --revisions-schema $db 1\nstdout 'Migrating to version 2 from 1 \\(1 migrations in total\\):'\ncmpshow users users.sql\n\natlas migrate apply --url URL --revisions-schema $db 1\nstdout 'Migrating to version 3 from 2 \\(1 migrations in total\\):'\ncmpshow users users.sql\ncmpshow pets pets.sql\n\natlas migrate apply --url URL --revisions-schema $db 1\nstdout 'No migration files to execute'\n\nclearSchema\n\natlas migrate apply --url URL --revisions-schema $db --log '{{ json . }}'\nvalidJSON stdout\nstdout '\"Driver\":\"mysql\"'\nstdout '\"Scheme\":\"mysql\"'\nstdout '\"Dir\":\"file://migrations\"'\nstdout '\"Target\":\"3\"'\nstdout '\"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\"}\\]'\nstdout '\"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;\"\\]'\nstdout '\"Start\":\"\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d.[0-9]'\n\n-- migrations/1_first.sql --\nCREATE 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;\n\n-- migrations/2_second.sql --\nALTER TABLE `users` ADD UNIQUE INDEX `age` (`age`);\n\n-- migrations/3_third.sql --\nCREATE TABLE `pets` (`id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_bin;\n\n-- users.sql --\nCREATE TABLE `users` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `age` bigint(20) NOT NULL,\n  `name` varchar(255) COLLATE utf8mb4_bin NOT NULL,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `age` (`age`)\n)\n\n-- mysql8/users.sql --\nCREATE TABLE `users` (\n  `id` bigint NOT NULL AUTO_INCREMENT,\n  `age` bigint NOT NULL,\n  `name` varchar(255) COLLATE utf8mb4_bin NOT NULL,\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `age` (`age`)\n)\n\n-- users_1.sql --\nCREATE TABLE `users` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `age` bigint(20) NOT NULL,\n  `name` varchar(255) COLLATE utf8mb4_bin NOT NULL,\n  PRIMARY KEY (`id`)\n)\n\n-- mysql8/users_1.sql --\nCREATE TABLE `users` (\n  `id` bigint NOT NULL AUTO_INCREMENT,\n  `age` bigint NOT NULL,\n  `name` varchar(255) COLLATE utf8mb4_bin NOT NULL,\n  PRIMARY KEY (`id`)\n)\n\n-- pets.sql --\nCREATE TABLE `pets` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT,\n  `name` varchar(255) COLLATE utf8mb4_bin NOT NULL,\n  PRIMARY KEY (`id`)\n)\n\n-- mysql8/pets.sql --\nCREATE TABLE `pets` (\n  `id` bigint NOT NULL AUTO_INCREMENT,\n  `name` varchar(255) COLLATE utf8mb4_bin NOT NULL,\n  PRIMARY KEY (`id`)\n)\n"
  },
  {
    "path": "internal/integration/testdata/mysql/cli-migrate-diff-format.txtar",
    "content": "only maria103\n\nmkdir migrations\n\n# old behavior still works\natlas migrate diff --dev-url URL --to file://1.hcl --dir-format golang-migrate first\ncmpmig 0 golang-migrate/1.down.sql\ncmpmig 1 golang-migrate/1.up.sql\n\natlas migrate diff --dev-url URL --to file://2.hcl --dir-format golang-migrate second\ncmpmig 2 golang-migrate/2.down.sql\ncmpmig 3 golang-migrate/2.up.sql\n\nrm migrations\nmkdir migrations\n\natlas migrate diff --dev-url URL --to file://1.hcl --dir file://migrations?format=golang-migrate first\ncmpmig 0 golang-migrate/1.down.sql\ncmpmig 1 golang-migrate/1.up.sql\n\natlas migrate diff --dev-url URL --to file://2.hcl --dir file://migrations?format=golang-migrate second\ncmpmig 2 golang-migrate/2.down.sql\ncmpmig 3 golang-migrate/2.up.sql\n\nrm migrations\nmkdir migrations\n\natlas migrate diff --dev-url URL --to file://1.hcl --dir file://migrations?format=goose first\ncmpmig 0 goose/1.sql\n\natlas migrate diff --dev-url URL --to file://2.hcl --dir file://migrations?format=goose second\ncmpmig 1 goose/2.sql\n\nrm migrations\nmkdir migrations\n\natlas migrate diff --dev-url URL --to file://1.hcl --dir file://migrations?format=dbmate first\ncmpmig 0 dbmate/1.sql\n\natlas migrate diff --dev-url URL --to file://2.hcl --dir file://migrations?format=dbmate second\ncmpmig 1 dbmate/2.sql\n\nrm migrations\nmkdir migrations\n\natlas migrate diff --dev-url URL --to file://1.hcl --dir file://migrations?format=flyway first\ncmpmig 0 flyway/U1.sql\ncmpmig 1 flyway/V1.sql\n\natlas migrate diff --dev-url URL --to file://2.hcl --dir file://migrations?format=flyway second\ncmpmig 1 flyway/U2.sql\ncmpmig 3 flyway/V2.sql\n\nrm migrations\nmkdir migrations\n\natlas migrate diff --dev-url URL --to file://1.hcl --dir file://migrations?format=liquibase first\ncmpmig 0 liquibase/1.sql\n\natlas migrate diff --dev-url URL --to file://2.hcl --dir file://migrations?format=liquibase second\ncmpmig 1 liquibase/2.sql\n\n-- golang-migrate/1.up.sql --\n-- create \"users\" table\nCREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\n\n-- golang-migrate/1.down.sql --\n-- reverse: create \"users\" table\nDROP TABLE `users`;\n\n-- golang-migrate/2.up.sql --\n-- modify \"users\" table\nALTER TABLE `users` ADD COLUMN `email` varchar(100) NULL;\n\n-- golang-migrate/2.down.sql --\n-- reverse: modify \"users\" table\nALTER TABLE `users` DROP COLUMN `email`;\n\n-- goose/1.sql --\n-- +goose Up\n-- create \"users\" table\nCREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\n\n-- +goose Down\n-- reverse: create \"users\" table\nDROP TABLE `users`;\n\n-- goose/2.sql --\n-- +goose Up\n-- modify \"users\" table\nALTER TABLE `users` ADD COLUMN `email` varchar(100) NULL;\n\n-- +goose Down\n-- reverse: modify \"users\" table\nALTER TABLE `users` DROP COLUMN `email`;\n\n-- dbmate/1.sql --\n-- migrate:up\n-- create \"users\" table\nCREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\n\n-- migrate:down\n-- reverse: create \"users\" table\nDROP TABLE `users`;\n\n-- dbmate/2.sql --\n-- migrate:up\n-- modify \"users\" table\nALTER TABLE `users` ADD COLUMN `email` varchar(100) NULL;\n\n-- migrate:down\n-- reverse: modify \"users\" table\nALTER TABLE `users` DROP COLUMN `email`;\n\n-- flyway/V1.sql --\n-- create \"users\" table\nCREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\n\n-- flyway/U1.sql --\n-- reverse: create \"users\" table\nDROP TABLE `users`;\n\n-- flyway/V2.sql --\n-- modify \"users\" table\nALTER TABLE `users` ADD COLUMN `email` varchar(100) NULL;\n\n-- flyway/U2.sql --\n-- reverse: modify \"users\" table\nALTER TABLE `users` DROP COLUMN `email`;\n\n-- liquibase/1.sql --\n--liquibase formatted sql\n--changeset atlas:0-0\n--comment: create \"users\" table\nCREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\n--rollback: DROP TABLE `users`;\n\n-- liquibase/2.sql --\n--liquibase formatted sql\n--changeset atlas:0-0\n--comment: modify \"users\" table\nALTER TABLE `users` ADD COLUMN `email` varchar(100) NULL;\n--rollback: ALTER TABLE `users` DROP COLUMN `email`;\n\n-- 1.hcl --\nschema \"script_cli_migrate_diff_format\" {}\n\ntable \"users\" {\n  schema = schema.script_cli_migrate_diff_format\n  column \"id\" {\n    null = false\n    type = bigint\n    auto_increment = true\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}\n\n-- 2.hcl --\nschema \"script_cli_migrate_diff_format\" {}\n\ntable \"users\" {\n  schema = schema.script_cli_migrate_diff_format\n  column \"id\" {\n    null = false\n    type = bigint\n    auto_increment = true\n  }\n  column \"email\" {\n    null = true\n    type = varchar(100)\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}"
  },
  {
    "path": "internal/integration/testdata/mysql/cli-migrate-diff-mode-normalized.txtar",
    "content": "only mysql\n\natlas migrate hash\n\n# Migrate diff wants to drop the unique index.\natlas migrate diff --dev-url URL --to file://./schema.sql\n! stdout 'no changes'\ncmpmig 1 expected.sql\n\n-- migrations/1.sql --\nCREATE TABLE `ref` (\n  `id` bigint NOT NULL AUTO_INCREMENT,\n  PRIMARY KEY (`id`)\n) CHARSET utf8mb4 COLLATE utf8mb4_bin;\nCREATE TABLE `tbl` (\n  `ref_id` bigint NOT NULL,\n  UNIQUE INDEX `u_ref_id` (`ref_id`), -- expected to be dropped\n  INDEX `ref_id` (`ref_id`),\n  FOREIGN KEY (`ref_id`) REFERENCES `ref` (`id`)\n) CHARSET utf8mb4 COLLATE utf8mb4_bin;\n\n-- schema.sql --\nCREATE TABLE `ref` (\n  `id` bigint NOT NULL AUTO_INCREMENT,\n  PRIMARY KEY (`id`)\n) CHARSET utf8mb4 COLLATE utf8mb4_bin;\nCREATE TABLE `tbl` (\n  `ref_id` bigint NOT NULL,\n  INDEX `ref_id` (`ref_id`),\n  FOREIGN KEY (`ref_id`) REFERENCES `ref` (`id`)\n) CHARSET utf8mb4 COLLATE utf8mb4_bin;\n\n-- expected.sql --\n-- Modify \"tbl\" table\nALTER TABLE `tbl` DROP INDEX `u_ref_id`;\n"
  },
  {
    "path": "internal/integration/testdata/mysql/cli-migrate-diff.txtar",
    "content": "only maria107 maria102\n\nexec mkdir migrations\n\n! atlas migrate diff --to file://1.hcl --dir file://migrations\nstderr '\"dev-url\" not set'\n\n! atlas migrate diff --dev-url mysql://devdb --dir file://migrations\nstderr '\"to\" not set'\n\natlas migrate diff --dev-url URL --to file://./1.hcl first\ncmpmig 0 1.sql\n\natlas migrate diff --dev-url URL --to file://./2.hcl second\ncmpmig 1 2.sql\n\n# Clean migration directory and run diff with a custom qualifier.\nexec rm -rf migrations\natlas migrate diff --dev-url URL --to file://./1.hcl --qualifier test first\ncmpmig 0 1-qualifier.sql\n\n-- 1.hcl --\nschema \"script_cli_migrate_diff\" {}\n\ntable \"users\" {\n  schema = schema.script_cli_migrate_diff\n  column \"id\" {\n    null = false\n    type = bigint\n    auto_increment = true\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}\n\n-- 1.sql --\n-- Create \"users\" table\nCREATE TABLE `users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\n\n-- 1-qualifier.sql --\n-- Create \"users\" table\nCREATE TABLE `test`.`users` (`id` bigint NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_general_ci;\n\n-- 2.hcl --\nschema \"script_cli_migrate_diff\" {}\n\ntable \"users\" {\n  schema = schema.script_cli_migrate_diff\n  column \"id\" {\n    null = false\n    type = bigint\n    auto_increment = true\n  }\n  column \"create_time\" {\n    null    = false\n    type    = timestamp(6)\n    default = sql(\"CURRENT_TIMESTAMP(6)\")\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}\n\n-- 2.sql --\n-- Modify \"users\" table\nALTER TABLE `users` ADD COLUMN `create_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6);\n\n-- maria102/2.sql --\n-- Modify \"users\" table\nALTER TABLE `users` ADD COLUMN `create_time` timestamp(6) NOT NULL DEFAULT (current_timestamp(6));\n\n-- maria107/2.sql --\n-- Modify \"users\" table\nALTER TABLE `users` ADD COLUMN `create_time` timestamp(6) NOT NULL DEFAULT (current_timestamp(6));\n"
  },
  {
    "path": "internal/integration/testdata/mysql/cli-project-schemas.txtar",
    "content": "atlas schema apply --env local --auto-approve > out.txt\nexec cat out.txt\nstdout 'CREATE TABLE `script_cli_project_schemas`'\n\n-- 1.hcl --\nschema \"script_cli_project_schemas\" {\n}\ntable \"users\" {\n   schema = schema.script_cli_project_schemas\n   column \"id\" {\n     type = bigint\n     null = false\n   }\n}\n-- atlas.hcl --\nenv \"local\" {\n    url = \"URL\"\n    src = \"./1.hcl\"\n    schemas = [\"script_cli_project_schemas\"]\n}\n-- expected.sql --\nCREATE TABLE `users` (\n  `id` bigint NOT NULL\n)\n-- 0.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}"
  },
  {
    "path": "internal/integration/testdata/mysql/cli-project-url-escape.txtar",
    "content": "only mysql8\n\nexecsql 'CREATE USER IF NOT EXISTS \"a8m\"@\"%\" IDENTIFIED BY \"&pass?\"'\nexecsql 'GRANT ALL PRIVILEGES ON *.* TO \"a8m\"@\"%\" WITH GRANT OPTION'\n\natlas schema inspect --env local > got.txt\ncmp got.txt want.txt\n\n! atlas schema inspect --env failed\nstderr 'invalid port \":&pass\" after host'\n\nexecsql 'DROP USER \"a8m\"@\"%\"'\n\n-- atlas.hcl --\nvariable \"pass\" {\n  type    = string\n  default = \"&pass?\"\n}\n\nlocals {\n  escaped_pass = urlescape(var.pass)\n}\n\nenv \"local\" {\n    url = \"mysql://a8m:${local.escaped_pass}@localhost:3308/script_cli_project_url_escape\"\n}\n\nenv \"failed\" {\n    url = \"mysql://a8m:${var.pass}@localhost:3308/script_cli_project_url_escape\"\n}\n\n-- want.txt --\nschema \"script_cli_project_url_escape\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_0900_ai_ci\"\n}"
  },
  {
    "path": "internal/integration/testdata/mysql/cli-schema-apply-datasrc.txtar",
    "content": "only mysql8\n\natlas schema apply --auto-approve --url URL --env dev --var \"url=URL\" --var \"pattern=script_cli_schema_apply_datasrc\"\nstdout '\\{\"Applied\":\\[\"CREATE TABLE `users` \\(\\\\n  `id` int NOT NULL\\\\n\\);*\"\\],\"Tenant\":\"script_cli_schema_apply_datasrc\"\\}'\n\n-- schema.hcl --\nvariable \"tenant\" {\n  type = string\n}\n\nschema \"test\" {\n  name = var.tenant\n}\n\ntable \"users\" {\n  schema = schema.test\n  column \"id\" {\n    type = int\n  }\n}\n\n-- atlas.hcl --\nvariable \"url\" {\n  type = string\n}\n\nvariable \"pattern\" {\n  type = string\n}\n\ndata \"sql\" \"tenants\" {\n  url = var.url\n  query = <<EOS\nSELECT `schema_name`\n  FROM `information_schema`.`schemata`\n  WHERE `schema_name` LIKE ?\nEOS\n  args = [var.pattern]\n}\n\nenv \"dev\" {\n  for_each = toset(data.sql.tenants.values)\n  url      = urlsetpath(var.url, each.value)\n  src      = \"schema.hcl\"\n  log {\n    schema {\n      apply = format(\n        \"{{ json .Changes | json_merge %q }}\\n\",\n        jsonencode({\n          Tenant : each.value\n        })\n      )\n    }\n  }\n  // Inject custom variables to our schema.\n  tenant = each.value\n}\n"
  },
  {
    "path": "internal/integration/testdata/mysql/column-add-drop.txtar",
    "content": "# Each test runs on a clean database.\n\n# Apply schema \"1.hcl\" on fresh database.\napply 1.hcl\n\n# Ensures tables exist in the database.\nexist users\n\n# Compare the result of \"SHOW TABLE users\" with the content of a file named '1.sql'.\n# The \"cmpshow\" command searches first a file named '<version>/1.sql' (version, defines\n# the database version), and in case it was found, it will use it instead.\ncmpshow users 1.sql\n\n# Apply schema \"2.hcl\" on the updated database.\napply 2.hcl\n\n# Compare database with 2.sql.\ncmpshow users 2.sql\n\n# Apply schema \"1.hcl\" should migrate database to previous state.\napply 1.hcl\ncmpshow users 1.sql\n\n# Drop table.\napply 0.hcl\n! exist users\n\n\n# Below files represent HCL and SQL. File names defined their index in\n# execution order. 1.hcl is executed first, 2.hcl executed second, etc.\n-- 1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    primary_key {\n        columns = [table.users.column.id]\n    }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `id` int(11) NOT NULL,\n  PRIMARY KEY (`id`)\n)\n\n-- mysql8/1.sql --\nCREATE TABLE `users` (\n  `id` int NOT NULL,\n  PRIMARY KEY (`id`)\n)\n\n-- 2.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema =  schema.$db\n    column \"id\" {\n        type = int\n    }\n    column \"name\" {\n        type = text\n    }\n    primary_key {\n        columns = [table.users.column.id]\n    }\n}\n\n-- 2.sql --\nCREATE TABLE `users` (\n  `id` int(11) NOT NULL,\n  `name` text NOT NULL,\n  PRIMARY KEY (`id`)\n)\n\n-- mysql8/2.sql --\nCREATE TABLE `users` (\n  `id` int NOT NULL,\n  `name` text NOT NULL,\n  PRIMARY KEY (`id`)\n)\n\n-- 0.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}"
  },
  {
    "path": "internal/integration/testdata/mysql/column-bit.txtar",
    "content": "apply 1.hcl\ncmpshow t 1.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"t\" {\n  schema = schema.$db\n  column \"c1\" {\n    type = bit\n  }\n  column \"c2\" {\n    type = bit(1)\n  }\n  column \"c3\" {\n    type = bit(64)\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `t` (\n  `c1` bit(1) NOT NULL,\n  `c2` bit(1) NOT NULL,\n  `c3` bit(64) NOT NULL\n)\n"
  },
  {
    "path": "internal/integration/testdata/mysql/column-bool.txtar",
    "content": "# Each test runs on a clean database.\n\napply 1.hcl\ncmpshow users 1.sql\n\n# \"bool\", \"boolean\" and \"tinyint(1)\" are equal.\nsynced 2.hcl\n\n# Changing \"tinyint(1)\" to \"tinyint\" should cause a schema change.\napply 3.hcl\ncmpshow users 3.sql\nsynced 3.hcl\n\n-- 1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"a\" {\n        type = bool\n    }\n    column \"b\" {\n        type = boolean\n    }\n    column \"c\" {\n        type = tinyint(1)\n    }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `a` tinyint(1) NOT NULL,\n  `b` tinyint(1) NOT NULL,\n  `c` tinyint(1) NOT NULL\n)\n\n-- 2.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"a\" {\n        type = boolean\n    }\n    column \"b\" {\n        type = tinyint(1)\n    }\n    column \"c\" {\n        type = bool\n    }\n}\n\n-- 3.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"a\" {\n        type = boolean\n    }\n    column \"b\" {\n        type = tinyint\n    }\n    column \"c\" {\n        type = bool\n    }\n}\n\n-- 3.sql --\nCREATE TABLE `users` (\n  `a` tinyint(1) NOT NULL,\n  `b` tinyint(4) NOT NULL,\n  `c` tinyint(1) NOT NULL\n)\n\n-- mysql8/3.sql --\nCREATE TABLE `users` (\n  `a` tinyint(1) NOT NULL,\n  `b` tinyint NOT NULL,\n  `c` tinyint(1) NOT NULL\n)\n"
  },
  {
    "path": "internal/integration/testdata/mysql/column-charset.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\n# Dropping the default COLLATE from the HCL does not have any effect.\napply 2.hcl\ncmpshow users 1.sql\n\n# Changing the default COLLATE to hebrew_bin.\napply 3.hcl\ncmpshow users 3.sql\n\n# Dropping custom COLLATE reverts to the default.\napply 4.hcl\ncmpshow users 1.sql\n\n# Dropping CHARSET and COLLATE.\napply 5.hcl\ncmpshow users 5.sql\n\n-- 1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"name\" {\n        type = varchar(255)\n        charset = \"hebrew\"\n        collate = \"hebrew_general_ci\"\n    }\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `name` varchar(255) CHARACTER SET hebrew NOT NULL\n)\n\n-- maria107/1.sql --\nCREATE TABLE `users` (\n  `name` varchar(255) CHARACTER SET hebrew COLLATE hebrew_general_ci NOT NULL\n)\n\n-- mysql8/1.sql --\nCREATE TABLE `users` (\n  `name` varchar(255) CHARACTER SET hebrew COLLATE hebrew_general_ci NOT NULL\n)\n\n-- 2.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"name\" {\n        type = varchar(255)\n        charset = \"hebrew\"\n    }\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\n-- 3.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"name\" {\n        type = varchar(255)\n        charset = \"hebrew\"\n        collate = \"hebrew_bin\"\n    }\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\n-- 3.sql --\nCREATE TABLE `users` (\n  `name` varchar(255) CHARACTER SET hebrew COLLATE hebrew_bin NOT NULL\n)\n\n-- 4.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"name\" {\n        type = varchar(255)\n        charset = \"hebrew\"\n    }\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\n-- 5.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"name\" {\n        type = varchar(255)\n    }\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\n-- 5.sql --\nCREATE TABLE `users` (\n  `name` varchar(255) NOT NULL\n)"
  },
  {
    "path": "internal/integration/testdata/mysql/column-default-expr.txtar",
    "content": "# Run tests only on MySQL 8.\nonly mysql8\n\n# Apply schema \"1.hcl\" on fresh database.\napply 1.hcl\n\n# Compare the result of \"SHOW TABLE users\" with the content of a file named '1.sql'.\ncmpshow users 1.sql\ncmphcl 1.hcl\n\n-- 1.hcl --\ntable \"users\" {\n  schema = schema.script_column_default_expr\n  column \"a\" {\n    null    = false\n    type    = varchar(255)\n    default = \"\"\n  }\n  column \"b\" {\n    null    = false\n    type    = varchar(255)\n    default = sql(\"(concat(_utf8mb4'a',`a`,_utf8mb4'\\\\'s',_utf8mb4'b'))\")\n  }\n  column \"c\" {\n    null    = false\n    type    = varchar(255)\n    default = \"a'b\"\n  }\n  column \"d\" {\n    null    = false\n    type    = varchar(255)\n    default = sql(\"(_utf8mb4'a\\\\'b')\")\n  }\n  column \"e\" {\n    null    = false\n    type    = timestamp\n    default = \"2000-01-01 00:00:00\"\n  }\n}\nschema \"script_column_default_expr\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_0900_ai_ci\"\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `a` varchar(255) NOT NULL DEFAULT '',\n  `b` varchar(255) NOT NULL DEFAULT (concat(_utf8mb4'a',`a`,_utf8mb4'\\'s',_utf8mb4'b')),\n  `c` varchar(255) NOT NULL DEFAULT 'a''b',\n  `d` varchar(255) NOT NULL DEFAULT (_utf8mb4'a\\'b'),\n  `e` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00'\n)"
  },
  {
    "path": "internal/integration/testdata/mysql/column-generated-inspect.txtar",
    "content": "# Skip MySQL 5.6 as it does not support generated columns.\n! only mysql56\n\napply 1.hcl\ncmphcl 1.inspect.hcl\n\n-- 1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"a\" {\n        type = bool\n        null = true\n    }\n    column \"b\" {\n        type = bool\n        null = true\n        as = \"a\"\n    }\n    column \"c\" {\n        type = bool\n        null = true\n        as {\n            type = STORED\n            expr = \"b\"\n        }\n    }\n    column \"d e\" {\n        null = false\n        type = varchar(255)\n    }\n    column \"d $\" {\n        null = false\n        type = varchar(255)\n    }\n    index \"idx_1\" {\n        columns = [column[\"d e\"]]\n    }\n    index \"idx_2\" {\n        columns = [column[\"d $\"]]\n    }\n}\n\n-- 1.inspect.hcl --\ntable \"users\" {\n  schema = schema.$db\n  column \"a\" {\n    null = true\n    type = bool\n  }\n  column \"b\" {\n    null = true\n    type = bool\n    as {\n      expr = \"`a`\"\n      type = VIRTUAL\n    }\n  }\n  column \"c\" {\n    null = true\n    type = bool\n    as {\n      expr = \"`b`\"\n      type = STORED\n    }\n  }\n  column \"d e\" {\n    null = false\n    type = varchar(255)\n  }\n  column \"d $\" {\n    null = false\n    type = varchar(255)\n  }\n  index \"idx_1\" {\n    columns = [column[\"d e\"]]\n  }\n  index \"idx_2\" {\n    columns = [column[\"d $\"]]\n  }\n}\nschema \"$db\" {\n  charset = \"$charset\"\n  collate = \"$collate\"\n}\n"
  },
  {
    "path": "internal/integration/testdata/mysql/column-generated.txtar",
    "content": "# Skip MySQL 5.6 as it does not support generated columns.\n! only mysql56\n\napply 1.hcl\ncmpshow users 1.sql\n\n! apply 2.fail1.hcl 'changing VIRTUAL generated column \"b\" to non-generated column is not supported (drop and add is required)'\n! apply 2.fail2.hcl 'changing column \"a\" to VIRTUAL generated column is not supported (drop and add is required)'\n! apply 2.fail3.hcl 'changing the store type of generated column \"c\" from \"STORED\" to \"VIRTUAL\" is not supported'\n\napply 3.hcl\ncmpshow users 3.sql\n\n-- 1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"a\" {\n        type = int\n    }\n    column \"b\" {\n        type = int\n        as = \"a * 2\"\n    }\n    column \"c\" {\n        type = int\n        as {\n            expr = \"a * b\"\n            type = STORED\n        }\n    }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `a` int(11) NOT NULL,\n  `b` int(11) GENERATED ALWAYS AS (`a` * 2) VIRTUAL,\n  `c` int(11) GENERATED ALWAYS AS (`a` * `b`) STORED\n)\n\n-- mysql57/1.sql --\nCREATE TABLE `users` (\n  `a` int(11) NOT NULL,\n  `b` int(11) GENERATED ALWAYS AS ((`a` * 2)) VIRTUAL NOT NULL,\n  `c` int(11) GENERATED ALWAYS AS ((`a` * `b`)) STORED NOT NULL\n)\n\n-- mysql8/1.sql --\nCREATE TABLE `users` (\n  `a` int NOT NULL,\n  `b` int GENERATED ALWAYS AS ((`a` * 2)) VIRTUAL NOT NULL,\n  `c` int GENERATED ALWAYS AS ((`a` * `b`)) STORED NOT NULL\n)\n\n-- 2.fail1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"a\" {\n        type = int\n    }\n    column \"b\" {\n        type = int\n    }\n    column \"c\" {\n        type = int\n        as {\n            expr = \"a * b\"\n            type = STORED\n        }\n    }\n}\n\n-- 2.fail2.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"a\" {\n        type = int\n        as = \"1\"\n    }\n    column \"b\" {\n        type = int\n        as = \"a * 2\"\n    }\n    column \"c\" {\n        type = int\n        as {\n            expr = \"a * b\"\n            type = VIRTUAL\n        }\n    }\n}\n\n-- 2.fail3.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"a\" {\n        type = int\n    }\n    column \"b\" {\n        type = int\n        as = \"a * 2\"\n    }\n    column \"c\" {\n        type = int\n        as {\n            expr = \"a * b\"\n            type = VIRTUAL\n        }\n    }\n}\n\n\n-- 3.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"a\" {\n        type = int\n        as {\n            expr = \"1\"\n            type = STORED\n        }\n    }\n    column \"b\" {\n        type = int\n        as = \"a * 3\"\n    }\n    column \"c\" {\n        type = int\n        as {\n            expr = \"a * b\"\n            type = STORED\n        }\n    }\n}\n\n-- 3.sql --\nCREATE TABLE `users` (\n  `a` int(11) GENERATED ALWAYS AS (1) STORED,\n  `b` int(11) GENERATED ALWAYS AS (`a` * 3) VIRTUAL,\n  `c` int(11) GENERATED ALWAYS AS (`a` * `b`) STORED\n)\n\n-- mysql57/3.sql --\nCREATE TABLE `users` (\n  `a` int(11) GENERATED ALWAYS AS (1) STORED NOT NULL,\n  `b` int(11) GENERATED ALWAYS AS ((`a` * 3)) VIRTUAL NOT NULL,\n  `c` int(11) GENERATED ALWAYS AS ((`a` * `b`)) STORED NOT NULL\n)\n\n-- mysql8/3.sql --\nCREATE TABLE `users` (\n  `a` int GENERATED ALWAYS AS (1) STORED NOT NULL,\n  `b` int GENERATED ALWAYS AS ((`a` * 3)) VIRTUAL NOT NULL,\n  `c` int GENERATED ALWAYS AS ((`a` * `b`)) STORED NOT NULL\n)\n"
  },
  {
    "path": "internal/integration/testdata/mysql/column-json.txtar",
    "content": "only maria*\n\napply 1.hcl\ncmpshow users 1.sql\n\n# The CHECK \"json_valid(`name`)\" should not be present in the HCL\n# description because the \"longtext\" is converted to \"json\" type.\ncmphcl 1.inspect.hcl\n\n-- 1.hcl --\nschema \"script_column_json\" {}\n\ntable \"users\" {\n  schema = schema.script_column_json\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"name\" {\n    null = false\n    type = json\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `id` int(11) NOT NULL,\n  `name` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`name`)),\n  PRIMARY KEY (`id`)\n)\n\n-- 1.inspect.hcl --\ntable \"users\" {\n  schema = schema.script_column_json\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"name\" {\n    null = false\n    type = json\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\nschema \"script_column_json\" {\n  charset = \"$charset\"\n  collate = \"$collate\"\n}"
  },
  {
    "path": "internal/integration/testdata/mysql/column-time-precision-maria.txtar",
    "content": "# Each test runs on a clean database.\nonly maria*\n\n# Apply schema \"1.hcl\" on fresh database.\napply 1.hcl\n\n# Compare the result of \"SHOW TABLE users\" with the content of a file named '1.sql'.\ncmpshow foo 1.sql\n\n# Files\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"foo\" {\n  schema    = schema.$db\n  column \"id\" {\n    null = false\n    type = char(36)\n  }\n  column \"precision_default\" {\n    null      = false\n    type      = timestamp\n    default   = sql(\"CURRENT_TIMESTAMP\")\n    on_update = sql(\"CURRENT_TIMESTAMP\")\n  }\n  column \"create_time\" {\n    null    = false\n    type    = timestamp(6)\n    default = sql(\"CURRENT_TIMESTAMP(6)\")\n  }\n  column \"update_time\" {\n    null    = false\n    type    = datetime(6)\n    default = sql(\"CURRENT_TIMESTAMP(6)\")\n    on_update = sql(\"CURRENT_TIMESTAMP(6)\")\n  }\n  primary_key {\n    columns = [table.foo.column.id, ]\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `foo` (\n  `id` char(36) NOT NULL,\n  `precision_default` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),\n  `create_time` timestamp(6) NOT NULL DEFAULT current_timestamp(6),\n  `update_time` datetime(6) NOT NULL DEFAULT current_timestamp(6) ON UPDATE current_timestamp(6),\n  PRIMARY KEY (`id`)\n)\n"
  },
  {
    "path": "internal/integration/testdata/mysql/column-time-precision-mysql.txtar",
    "content": "# Each test runs on a clean database.\nonly mysql56 mysql57 mysql8\n\n# Apply schema \"1.hcl\" on fresh database.\napply 1.hcl\n\n# Compare the result of \"SHOW TABLE users\" with the content of a file named '1.sql'.\ncmpshow foo 1.sql\n\n# Files\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"foo\" {\n  schema    = schema.$db\n  column \"id\" {\n    null = false\n    type = char(36)\n  }\n  column \"precision_default\" {\n    null      = false\n    type      = timestamp\n    default   = sql(\"CURRENT_TIMESTAMP\")\n    on_update = sql(\"CURRENT_TIMESTAMP\")\n  }\n  column \"create_time\" {\n    null    = false\n    type    = timestamp(6)\n    default = sql(\"CURRENT_TIMESTAMP(6)\")\n  }\n  column \"update_time\" {\n    null    = false\n    type    = datetime(6)\n    default = sql(\"CURRENT_TIMESTAMP(6)\")\n    on_update = sql(\"CURRENT_TIMESTAMP(6)\")\n  }\n  primary_key {\n    columns = [table.foo.column.id, ]\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `foo` (\n  `id` char(36) NOT NULL,\n  `precision_default` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  `create_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),\n  `update_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),\n  PRIMARY KEY (`id`)\n)\n"
  },
  {
    "path": "internal/integration/testdata/mysql/foreign-key-add.txtar",
    "content": "# Each test runs on a clean database.\n\n# Apply schema \"1.hcl\" on fresh database.\napply 1.hcl\n# Check that users exists in the database.\nexist users\n\n# The negate version indicates that this command is expected to fail and the\n# second argument is an optional pattern for matching on the returned error.\n! apply invalid-on-delete-action.hcl 'foreign key constraint was \"author_id\" SET NULL, but column \"author_id\" is NOT NULL'\n! apply invalid-on-update-action.hcl 'foreign key constraint was \"author_id\" SET NULL, but column \"author_id\" is NOT NULL'\n\napply 2.hcl\nexist users posts\ncmpshow users posts 2.sql\n\n# Below files represent HCL and SQL. File names defined their index in\n# execution order. 1.hcl is executed first, 2.hcl executed second, etc.\n-- 1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    primary_key {\n        columns = [table.users.column.id]\n    }\n}\n\n-- invalid-on-delete-action.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    primary_key {\n        columns = [table.users.column.id]\n    }\n}\n\ntable \"posts\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    column \"author_id\" {\n        type = int\n    }\n    primary_key {\n        columns = [table.posts.column.id]\n    }\n    foreign_key \"owner_id\" {\n        columns = [table.posts.column.author_id]\n        ref_columns = [table.users.column.id]\n        on_delete = SET_NULL\n    }\n}\n\n-- invalid-on-update-action.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    primary_key {\n        columns = [table.users.column.id]\n    }\n}\n\ntable \"posts\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    column \"author_id\" {\n        type = int\n    }\n    primary_key {\n        columns = [table.posts.column.id]\n    }\n    foreign_key \"owner_id\" {\n    \tcolumns = [table.posts.column.author_id]\n    \tref_columns = [table.users.column.id]\n    \ton_update = SET_NULL\n    }\n}\n\n-- 2.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    primary_key {\n        columns = [table.users.column.id]\n    }\n}\n\ntable \"posts\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    column \"author_id\" {\n        type = int\n        null = true\n    }\n    primary_key {\n        columns = [table.posts.column.id]\n    }\n    foreign_key \"owner_id\" {\n    \tcolumns = [table.posts.column.author_id]\n    \tref_columns = [table.users.column.id]\n    \ton_delete = SET_NULL\n    }\n}\n\n-- 2.sql --\nCREATE TABLE `users` (\n  `id` int(11) NOT NULL,\n  PRIMARY KEY (`id`)\n)\nCREATE TABLE `posts` (\n  `id` int(11) NOT NULL,\n  `author_id` int(11) DEFAULT NULL,\n  PRIMARY KEY (`id`),\n  KEY `owner_id` (`author_id`),\n  CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE SET NULL\n)\n\n-- mysql8/2.sql --\nCREATE TABLE `users` (\n  `id` int NOT NULL,\n  PRIMARY KEY (`id`)\n)\nCREATE TABLE `posts` (\n  `id` int NOT NULL,\n  `author_id` int DEFAULT NULL,\n  PRIMARY KEY (`id`),\n  KEY `owner_id` (`author_id`),\n  CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE SET NULL\n)\n"
  },
  {
    "path": "internal/integration/testdata/mysql/foreign-key-modify-action.txtar",
    "content": "# Each test runs on a clean database.\n\n# Apply schema \"1.hcl\" on fresh database.\napply 1.hcl\ncmpshow users posts 1.sql\n\napply 2.hcl\ncmpshow users posts 2.sql\n\n# Below files represent HCL and SQL. File names defined their index in\n# execution order. 1.hcl is executed first, 2.hcl executed second, etc.\n-- 1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    primary_key {\n        columns = [table.users.column.id]\n    }\n}\n\ntable \"posts\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    column \"author_id\" {\n        type = int\n        null = true\n    }\n    primary_key {\n        columns = [table.posts.column.id]\n    }\n    foreign_key \"owner_id\" {\n    \tcolumns = [table.posts.column.author_id]\n    \tref_columns = [table.users.column.id]\n    \ton_update = SET_NULL\n    }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `id` int(11) NOT NULL,\n  PRIMARY KEY (`id`)\n)\nCREATE TABLE `posts` (\n  `id` int(11) NOT NULL,\n  `author_id` int(11) DEFAULT NULL,\n  PRIMARY KEY (`id`),\n  KEY `owner_id` (`author_id`),\n  CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON UPDATE SET NULL\n)\n\n-- mysql8/1.sql --\nCREATE TABLE `users` (\n  `id` int NOT NULL,\n  PRIMARY KEY (`id`)\n)\nCREATE TABLE `posts` (\n  `id` int NOT NULL,\n  `author_id` int DEFAULT NULL,\n  PRIMARY KEY (`id`),\n  KEY `owner_id` (`author_id`),\n  CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON UPDATE SET NULL\n)\n\n-- 2.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    primary_key {\n        columns = [table.users.column.id]\n    }\n}\n\ntable \"posts\" {\n    schema = schema.$db\n    column \"id\" {\n        type = int\n    }\n    column \"author_id\" {\n        type = int\n        null = true\n    }\n    primary_key {\n        columns = [table.posts.column.id]\n    }\n    foreign_key \"owner_id\" {\n    \tcolumns = [table.posts.column.author_id]\n    \tref_columns = [table.users.column.id]\n    \ton_update = NO_ACTION\n    \ton_delete = CASCADE\n    }\n}\n\n-- 2.sql --\nCREATE TABLE `users` (\n  `id` int(11) NOT NULL,\n  PRIMARY KEY (`id`)\n)\nCREATE TABLE `posts` (\n  `id` int(11) NOT NULL,\n  `author_id` int(11) DEFAULT NULL,\n  PRIMARY KEY (`id`),\n  KEY `owner_id` (`author_id`),\n  CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION\n)\n\n-- mysql8/2.sql --\nCREATE TABLE `users` (\n  `id` int NOT NULL,\n  PRIMARY KEY (`id`)\n)\nCREATE TABLE `posts` (\n  `id` int NOT NULL,\n  `author_id` int DEFAULT NULL,\n  PRIMARY KEY (`id`),\n  KEY `owner_id` (`author_id`),\n  CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE CASCADE\n)"
  },
  {
    "path": "internal/integration/testdata/mysql/foreign-key.txtar",
    "content": "only mysql8 maria107\n\napply 1.hcl\ncmpshow t1 t1.sql\ncmpshow t2 t2.sql\ncmphcl 1.inspect.hcl\n\n-- 1.hcl --\nschema \"$db\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}\n\ntable \"t1\" {\n  schema = schema.$db\n  column \"c1\" {\n    null = false\n    type = int\n  }\n  column \"c2\" {\n    null = true\n    type = int\n  }\n  column \"c3\" {\n    null = true\n    type = int\n  }\n  primary_key {\n    columns = [column.c1]\n  }\n  index \"t1_c2_c3_idx\" {\n    unique  = true\n    columns = [column.c2, column.c3]\n  }\n}\ntable \"t2\" {\n  schema = schema.$db\n  column \"c1\" {\n    null = false\n    type = int\n  }\n  column \"c2\" {\n    null = true\n    type = int\n  }\n  column \"c3\" {\n    null = true\n    type = int\n  }\n  primary_key {\n    columns = [column.c1]\n  }\n  foreign_key \"c2_c3_1\" {\n    columns     = [column.c2, column.c3]\n    ref_columns = [table.t1.column.c2, table.t1.column.c3]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n  foreign_key \"c2_c3_2\" {\n    columns     = [column.c2, column.c3]\n    ref_columns = [table.t1.column.c2, table.t1.column.c3]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n}\n\n-- mysql8/t1.sql --\nCREATE TABLE `t1` (\n  `c1` int NOT NULL,\n  `c2` int DEFAULT NULL,\n  `c3` int DEFAULT NULL,\n  PRIMARY KEY (`c1`),\n  UNIQUE KEY `t1_c2_c3_idx` (`c2`,`c3`)\n)\n\n-- mysql8/t2.sql --\nCREATE TABLE `t2` (\n  `c1` int NOT NULL,\n  `c2` int DEFAULT NULL,\n  `c3` int DEFAULT NULL,\n  PRIMARY KEY (`c1`),\n  KEY `c2_c3_2` (`c2`,`c3`),\n  CONSTRAINT `c2_c3_1` FOREIGN KEY (`c2`, `c3`) REFERENCES `t1` (`c2`, `c3`),\n  CONSTRAINT `c2_c3_2` FOREIGN KEY (`c2`, `c3`) REFERENCES `t1` (`c2`, `c3`)\n)\n\n-- t1.sql --\nCREATE TABLE `t1` (\n  `c1` int(11) NOT NULL,\n  `c2` int(11) DEFAULT NULL,\n  `c3` int(11) DEFAULT NULL,\n  PRIMARY KEY (`c1`),\n  UNIQUE KEY `t1_c2_c3_idx` (`c2`,`c3`)\n)\n\n-- t2.sql --\nCREATE TABLE `t2` (\n  `c1` int(11) NOT NULL,\n  `c2` int(11) DEFAULT NULL,\n  `c3` int(11) DEFAULT NULL,\n  PRIMARY KEY (`c1`),\n  KEY `c2_c3_2` (`c2`,`c3`),\n  CONSTRAINT `c2_c3_1` FOREIGN KEY (`c2`, `c3`) REFERENCES `t1` (`c2`, `c3`) ON DELETE NO ACTION ON UPDATE NO ACTION,\n  CONSTRAINT `c2_c3_2` FOREIGN KEY (`c2`, `c3`) REFERENCES `t1` (`c2`, `c3`) ON DELETE NO ACTION ON UPDATE NO ACTION\n)\n\n-- 1.inspect.hcl --\ntable \"t1\" {\n  schema = schema.script_foreign_key\n  column \"c1\" {\n    null = false\n    type = int\n  }\n  column \"c2\" {\n    null = true\n    type = int\n  }\n  column \"c3\" {\n    null = true\n    type = int\n  }\n  primary_key {\n    columns = [column.c1]\n  }\n  index \"t1_c2_c3_idx\" {\n    unique  = true\n    columns = [column.c2, column.c3]\n  }\n}\ntable \"t2\" {\n  schema = schema.script_foreign_key\n  column \"c1\" {\n    null = false\n    type = int\n  }\n  column \"c2\" {\n    null = true\n    type = int\n  }\n  column \"c3\" {\n    null = true\n    type = int\n  }\n  primary_key {\n    columns = [column.c1]\n  }\n  foreign_key \"c2_c3_1\" {\n    columns     = [column.c2, column.c3]\n    ref_columns = [table.t1.column.c2, table.t1.column.c3]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n  foreign_key \"c2_c3_2\" {\n    columns     = [column.c2, column.c3]\n    ref_columns = [table.t1.column.c2, table.t1.column.c3]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n  index \"c2_c3_2\" {\n    columns = [column.c2, column.c3]\n  }\n}\nschema \"script_foreign_key\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}"
  },
  {
    "path": "internal/integration/testdata/mysql/index-add-drop.txtar",
    "content": "# Each test runs on a clean database.\n\n# Apply schema \"1.hcl\" on fresh database.\napply 1.hcl\ncmpshow users 1.sql\n\n# Add index to table \"users\".\napply 2.hcl\ncmpshow users 2.sql\n\n# Drop uniqueness from index.\napply 3.hcl\ncmpshow users 3.sql\n\n# Drop index.\napply 1.hcl\ncmpshow users 1.sql\n\n# Below files represent HCL and SQL. File names defined their index in\n# execution order. 1.hcl is executed first, 2.hcl executed second, etc.\n-- 1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = bigint\n    }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `rank` bigint(20) NOT NULL\n)\n\n-- mysql8/1.sql --\nCREATE TABLE `users` (\n  `rank` bigint NOT NULL\n)\n\n-- 2.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = bigint\n    }\n    index \"rank_idx\" {\n        unique  = true\n        columns = [table.users.column.rank]\n    }\n}\n\n-- 2.sql --\nCREATE TABLE `users` (\n  `rank` bigint(20) NOT NULL,\n  UNIQUE KEY `rank_idx` (`rank`)\n)\n\n-- mysql8/2.sql --\nCREATE TABLE `users` (\n  `rank` bigint NOT NULL,\n  UNIQUE KEY `rank_idx` (`rank`)\n)\n\n\n-- 3.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = bigint\n    }\n    index \"rank_idx\" {\n        columns = [table.users.column.rank]\n    }\n}\n\n-- 3.sql --\nCREATE TABLE `users` (\n  `rank` bigint(20) NOT NULL,\n  KEY `rank_idx` (`rank`)\n)\n\n-- mysql8/3.sql --\nCREATE TABLE `users` (\n  `rank` bigint NOT NULL,\n  KEY `rank_idx` (`rank`)\n)"
  },
  {
    "path": "internal/integration/testdata/mysql/index-desc.txtar",
    "content": "# Each test runs on a clean database.\n\n# Run this test only on MySQL 8 as it is not supported by other versions.\nonly mysql8\n\n# Apply schema \"1.hcl\" on fresh database.\napply 1.hcl\ncmpshow users 1.sql\n\n# Drop the \"DESC\" option from the key part.\napply 2.hcl\ncmpshow users 2.sql\n# Use of \"columns\" instead of \"on\" should not trigger a change.\nsynced 2-no-change.hcl\n\napply 3.hcl\ncmpshow users 3.sql\n\n# Below files represent HCL and SQL. File names defined their index in\n# execution order. 1.hcl is executed first, 2.hcl executed second, etc.\n-- 1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = bigint\n    }\n    index \"rank_idx\" {\n        on {\n            desc   = true\n            column = table.users.column.rank\n        }\n    }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `rank` bigint NOT NULL,\n  KEY `rank_idx` (`rank` DESC)\n)\n\n-- 2.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = bigint\n    }\n    index \"rank_idx\" {\n        on {\n            column = table.users.column.rank\n        }\n    }\n}\n\n-- 2.sql --\nCREATE TABLE `users` (\n  `rank` bigint NOT NULL,\n  KEY `rank_idx` (`rank`)\n)\n\n\n-- 2-no-change.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = bigint\n    }\n    index \"rank_idx\" {\n        columns = [\n            table.users.column.rank,\n        ]\n    }\n}\n\n-- 3.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = bigint\n    }\n    column \"score\" {\n        type = int\n    }\n    index \"rank_score_idx\" {\n        on {\n            column = table.users.column.rank\n        }\n        on {\n            column = table.users.column.score\n            desc = true\n        }\n    }\n}\n\n-- 3.sql --\nCREATE TABLE `users` (\n  `rank` bigint NOT NULL,\n  `score` int NOT NULL,\n  KEY `rank_score_idx` (`rank`,`score` DESC)\n)\n"
  },
  {
    "path": "internal/integration/testdata/mysql/index-expr.txtar",
    "content": "# Run this test only on MySQL 8 as it is not supported by other versions.\nonly mysql8\n\napply 1.hcl\ncmpshow users 1.sql\n\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"first_name\" {\n    null = false\n    type = varchar(128)\n  }\n  column \"last_name\" {\n    null = false\n    type = varchar(128)\n  }\n  index \"full_name\" {\n    on {\n        expr = \"concat(`first_name`, `last_name`)\"\n    }\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `first_name` varchar(128) NOT NULL,\n  `last_name` varchar(128) NOT NULL,\n  KEY `full_name` ((concat(`first_name`,`last_name`)))\n)\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"first_name\" {\n    null = false\n    type = varchar(128)\n  }\n  column \"last_name\" {\n    null = false\n    type = varchar(128)\n  }\n  index \"full_name\" {\n    on {\n      expr = \"concat(`first_name`, '\\\\'s first name')\"\n    }\n  }\n}\n\n-- 2.sql --\nCREATE TABLE `users` (\n  `first_name` varchar(128) NOT NULL,\n  `last_name` varchar(128) NOT NULL,\n  KEY `full_name` ((concat(`first_name`,_utf8mb4'\\'s first name')))\n)"
  },
  {
    "path": "internal/integration/testdata/mysql/index-prefix.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\n# Change prefix.\napply 2.hcl\ncmpshow users 2.sql\n\n# Drop prefix.\napply 3.hcl\ncmpshow users 3.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    type = varchar(255)\n  }\n  index \"user_name\" {\n    on {\n      column = column.name\n      prefix = 64\n    }\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `name` varchar(255) NOT NULL,\n  KEY `user_name` (`name`(64))\n)\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    type = varchar(255)\n  }\n  index \"user_name\" {\n    on {\n      column = column.name\n      prefix = 128\n    }\n  }\n}\n\n-- 2.sql --\nCREATE TABLE `users` (\n  `name` varchar(255) NOT NULL,\n  KEY `user_name` (`name`(128))\n)\n\n-- 3.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    type = varchar(128)\n  }\n  index \"user_name\" {\n    on {\n      column = column.name\n    }\n  }\n}\n\n-- 3.sql --\nCREATE TABLE `users` (\n  `name` varchar(128) NOT NULL,\n  KEY `user_name` (`name`)\n)"
  },
  {
    "path": "internal/integration/testdata/mysql/index-type.txtar",
    "content": "only mysql8 mysql57\n\napply 1.hcl\ncmpshow users 1.sql\n\n# Drop an index.\napply 2.hcl\ncmpshow users 2.sql\n\natlas schema inspect --url file://schema.v1.sql --dev-url DEV_URL --format '{{ sql . }}'\nstdout '-- Create \"geom\" table'\nstdout 'CREATE TABLE `geom` \\(`g` geometry NOT NULL, SPATIAL INDEX `idx` \\(`g`\\)\\) .*'\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"text\" {\n    null = false\n    type = text\n  }\n  index \"users_text\" {\n    type = FULLTEXT\n    columns = [column.text]\n  }\n  index \"ngram_text\" {\n    type = FULLTEXT\n    parser = ngram\n    columns = [column.text]\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `text` text NOT NULL,\n  FULLTEXT KEY `ngram_text` (`text`) /*!50100 WITH PARSER `ngram` */ ,\n  FULLTEXT KEY `users_text` (`text`)\n)\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"text\" {\n    null = false\n    type = text\n  }\n}\n\n-- 2.sql --\nCREATE TABLE `users` (\n  `text` text NOT NULL\n)\n-- schema.v1.sql --\nCREATE TABLE geom (g GEOMETRY NOT NULL);\nCREATE SPATIAL INDEX idx ON geom (g);\n\n"
  },
  {
    "path": "internal/integration/testdata/mysql/index-unique.txtar",
    "content": "apply 1.hcl\ncmpshow t 1.sql\n\n# Insert a few records to the table, and cause the new desired change to fail.\nexecsql 'INSERT INTO $db.t (c, d) VALUES (1, 1), (1, 2), (1, 3)'\n! apply 2.fail.hcl \"Error 1062: Duplicate entry '1' for key 'c'\"\n\napply 2.hcl\ncmpshow t 2.sql\n\n-- 1.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"t\" {\n    schema = schema.$db\n    column \"c\" {\n        type = bigint\n    }\n    column \"d\" {\n        type = bigint\n    }\n    index \"c\" {\n        unique = true\n        columns = [column.c, column.d]\n    }\n}\n\n-- 1.sql --\nCREATE TABLE `t` (\n  `c` bigint(20) NOT NULL,\n  `d` bigint(20) NOT NULL,\n  UNIQUE KEY `c` (`c`,`d`)\n)\n\n-- mysql8/1.sql --\nCREATE TABLE `t` (\n  `c` bigint NOT NULL,\n  `d` bigint NOT NULL,\n  UNIQUE KEY `c` (`c`,`d`)\n)\n\n-- 2.fail.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"t\" {\n    schema = schema.$db\n    column \"c\" {\n        type = bigint\n    }\n    index \"c\" {\n        unique = true\n        columns = [column.c]\n    }\n}\n\n-- 2.hcl --\nschema \"$db\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"t\" {\n    schema = schema.$db\n    column \"c\" {\n        type = bigint\n    }\n    index \"c\" {\n        columns = [column.c]\n    }\n}\n\n-- 2.sql --\nCREATE TABLE `t` (\n  `c` bigint(20) NOT NULL,\n  KEY `c` (`c`)\n)\n\n-- mysql8/2.sql --\nCREATE TABLE `t` (\n  `c` bigint NOT NULL,\n  KEY `c` (`c`)\n)"
  },
  {
    "path": "internal/integration/testdata/mysql/primary-key-parts.txtar",
    "content": "only mysql8\n\n# Version 1.\natlas schema inspect --url file://schema.v1.sql --dev-url URL > got\ncmp got schema.v1.hcl\natlas schema inspect --url file://schema.v1.hcl --dev-url URL > got\ncmp got schema.v1.hcl\natlas migrate diff v1 --to file://schema.v1.hcl --dev-url URL\ncmpmig 0 migration.v1.sql\natlas migrate diff v1-check --to file://schema.v1.hcl --dev-url URL\nstdout 'The migration directory is synced with the desired state, no changes to be made'\n\n# Version 2.\natlas migrate diff v2 --to file://schema.v2.hcl --dev-url URL\ncmpmig 1 migration.v2.sql\natlas migrate diff v2-check --to file://schema.v2.hcl --dev-url URL\nstdout 'The migration directory is synced with the desired state, no changes to be made'\n\n-- schema.v1.sql --\nCREATE TABLE `t1` (`id` tinytext NOT NULL, PRIMARY KEY (`id` (7)));\nCREATE TABLE `t2` (`id` tinytext NOT NULL, PRIMARY KEY (`id` (7) DESC));\n-- schema.v1.hcl --\ntable \"t1\" {\n  schema = schema.script_primary_key_parts\n  column \"id\" {\n    null = false\n    type = tinytext\n  }\n  primary_key {\n    on {\n      column = column.id\n      prefix = 7\n    }\n  }\n}\ntable \"t2\" {\n  schema = schema.script_primary_key_parts\n  column \"id\" {\n    null = false\n    type = tinytext\n  }\n  primary_key {\n    on {\n      desc   = true\n      column = column.id\n      prefix = 7\n    }\n  }\n}\nschema \"script_primary_key_parts\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_0900_ai_ci\"\n}\n-- migration.v1.sql --\n-- Create \"t1\" table\nCREATE TABLE `t1` (`id` tinytext NOT NULL, PRIMARY KEY (`id` (7))) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;\n-- Create \"t2\" table\nCREATE TABLE `t2` (`id` tinytext NOT NULL, PRIMARY KEY (`id` (7) DESC)) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;\n-- schema.v2.hcl --\ntable \"t1\" {\n  schema = schema.script_primary_key_parts\n  column \"id\" {\n    null = false\n    type = tinytext\n  }\n  column \"id2\" {\n    null = false\n    type = tinytext\n  }\n  primary_key {\n    on {\n      column = column.id\n      prefix = 7\n    }\n    on {\n      column = column.id2\n      prefix = 1\n    }\n  }\n}\ntable \"t2\" {\n  schema = schema.script_primary_key_parts\n  column \"id\" {\n    null = false\n    type = tinytext\n  }\n  primary_key {\n    on {\n      desc   = false\n      column = column.id\n      prefix = 6\n    }\n  }\n}\nschema \"script_primary_key_parts\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_0900_ai_ci\"\n}\n-- migration.v2.sql --\n-- Modify \"t1\" table\nALTER TABLE `t1` ADD COLUMN `id2` tinytext NOT NULL, DROP PRIMARY KEY, ADD PRIMARY KEY (`id` (7), `id2` (1));\n-- Modify \"t2\" table\nALTER TABLE `t2` DROP PRIMARY KEY, ADD PRIMARY KEY (`id` (6));\n"
  },
  {
    "path": "internal/integration/testdata/mysql/primary-key.txtar",
    "content": "only mysql8\n\n# Create table.\napply 1.hcl\ncmpshow users 1.sql\n\n# Add a primary-key.\napply 2.hcl\ncmpshow users 2.sql\n\n# Modify the primary-key column and type.\napply 3.hcl\ncmpshow users 3.sql\n\n# Drop the primary-key.\napply 1.hcl\ncmpshow users 1.sql\n\n-- 1.hcl --\nschema \"$db\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"id\" {\n    null = false\n    type = varchar(128)\n  }\n  column \"oid\" {\n    null = false\n    type = varchar(128)\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (\n  `id` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,\n  `oid` varchar(128) COLLATE utf8mb4_general_ci NOT NULL\n)\n\n-- 2.hcl --\nschema \"$db\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"id\" {\n    null = false\n    type = varchar(128)\n  }\n  column \"oid\" {\n    null = false\n    type = varchar(128)\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\n\n-- 2.sql --\nCREATE TABLE `users` (\n  `id` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,\n  `oid` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,\n  PRIMARY KEY (`id`)\n)\n\n\n-- 3.hcl --\nschema \"$db\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_general_ci\"\n}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"id\" {\n    null = false\n    type = varchar(128)\n  }\n  column \"oid\" {\n    null = false\n    type = varchar(128)\n  }\n  primary_key {\n    columns = [column.oid]\n    type    = HASH\n  }\n}\n\n-- 3.sql --\nCREATE TABLE `users` (\n  `id` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,\n  `oid` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,\n  PRIMARY KEY (`oid`)\n)\n"
  },
  {
    "path": "internal/integration/testdata/mysql/table-engine.txtar",
    "content": "only mysql8\n\n# InnoDB as the default storage engine.\napply 1.hcl\ncmphcl 1.inspect.hcl\n\n# Change the InnoDB (default storage engine) to MyISAM.\napply 2.hcl\ncmphcl 2.inspect.hcl\n\n# Drop MyISAM changes the engine to the default (InnoDB).\napply 3.hcl\ncmphcl 3.inspect.hcl\n\n-- 1.hcl --\nschema \"script_table_engine\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    engine = InnoDB\n    column \"name\" {\n      null = false\n      type = varchar(255)\n    }\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\n-- 1.inspect.hcl --\ntable \"users\" {\n  schema = schema.script_table_engine\n  column \"name\" {\n    null = false\n    type = varchar(255)\n  }\n}\nschema \"script_table_engine\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_0900_ai_ci\"\n}\n-- 2.hcl --\nschema \"script_table_engine\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    engine = MyISAM\n    column \"name\" {\n      null = false\n      type = varchar(255)\n    }\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n-- 2.inspect.hcl --\ntable \"users\" {\n  schema = schema.script_table_engine\n  engine = MyISAM\n  column \"name\" {\n    null = false\n    type = varchar(255)\n  }\n}\nschema \"script_table_engine\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_0900_ai_ci\"\n}\n-- 3.hcl --\nschema \"script_table_engine\" {\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"name\" {\n      null = false\n      type = varchar(255)\n    }\n    charset = \"$charset\"\n    collate = \"$collate\"\n}\n-- 3.inspect.hcl --\ntable \"users\" {\n  schema = schema.script_table_engine\n  column \"name\" {\n    null = false\n    type = varchar(255)\n  }\n}\nschema \"script_table_engine\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_0900_ai_ci\"\n}"
  },
  {
    "path": "internal/integration/testdata/postgres/cli-inspect-file.txtar",
    "content": "# inspect without dev-db will failed\n! atlas schema inspect -u file://a.sql\nstderr 'Error: --dev-url cannot be empty'\n\n# inspect file to HCL\natlas schema inspect -u file://a.sql --dev-url URL > inspected.hcl\ncmp inspected.hcl script_cli_inspect.hcl\n\n# inspect file to SQL\natlas schema inspect -u file://a.sql --dev-url URL --format '{{ sql . }}' > inspected.sql\ncmp inspected.sql script_cli_inspect.sql\n\n-- a.sql --\ncreate table users (\n  id int NOT NULL,\n  PRIMARY KEY (id)\n)\n\n-- script_cli_inspect.hcl --\ntable \"users\" {\n  schema = schema.script_cli_inspect_file\n  column \"id\" {\n    null = false\n    type = integer\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\nschema \"script_cli_inspect_file\" {\n}\n-- script_cli_inspect.sql --\n-- Create \"users\" table\nCREATE TABLE \"users\" (\"id\" integer NOT NULL, PRIMARY KEY (\"id\"));\n"
  },
  {
    "path": "internal/integration/testdata/postgres/cli-inspect.txtar",
    "content": "apply 1.hcl\n\n# test url flag\natlas schema inspect -u URL > inspected.hcl\ncmp inspected.hcl script_cli_inspect.hcl\n\n# test exclude flag on table.\natlas schema inspect -u URL --exclude \"users\" > inspected.hcl\ncmp inspected.hcl notable.hcl\n\n# test exclude flag on column.\natlas schema inspect -u URL --exclude \"*.[ab]*\" > inspected.hcl\ncmp inspected.hcl id.hcl\n\n# test exclude flag on column.\natlas schema inspect -u URL --exclude \"*.*\" > inspected.hcl\ncmp inspected.hcl nocolumn.hcl\n\n\n-- 1.hcl --\ntable \"users\" {\n  schema = schema.$db\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"a\" {\n    null = false\n    type = int\n  }\n  column \"b\" {\n    null = false\n    type = int\n  }\n  column \"ab\" {\n    null = false\n    type = int\n  }\n  column \"ac\" {\n    null = false\n    type = int4\n  }\n}\nschema \"$db\" {\n}\n\n-- script_cli_inspect.hcl --\ntable \"users\" {\n  schema = schema.script_cli_inspect\n  column \"id\" {\n    null = false\n    type = integer\n  }\n  column \"a\" {\n    null = false\n    type = integer\n  }\n  column \"b\" {\n    null = false\n    type = integer\n  }\n  column \"ab\" {\n    null = false\n    type = integer\n  }\n  column \"ac\" {\n    null = false\n    type = integer\n  }\n}\nschema \"script_cli_inspect\" {\n}\n-- empty.hcl --\n-- notable.hcl --\nschema \"script_cli_inspect\" {\n}\n-- id.hcl --\ntable \"users\" {\n  schema = schema.script_cli_inspect\n  column \"id\" {\n    null = false\n    type = integer\n  }\n}\nschema \"script_cli_inspect\" {\n}\n-- nocolumn.hcl --\ntable \"users\" {\n  schema = schema.script_cli_inspect\n}\nschema \"script_cli_inspect\" {\n}"
  },
  {
    "path": "internal/integration/testdata/postgres/cli-migrate-apply-datasrc.txtar",
    "content": "only postgres14\n\natlas migrate hash\natlas migrate apply --url URL --env dev --var \"url=URL\" --var \"pattern=script_cli_migrate_apply_datasrc\"\nstdout 'Migrating to version 1 \\(1 migrations in total\\):'\n\n-- atlas.hcl --\nvariable \"url\" {\n  type = string\n}\n\nvariable \"pattern\" {\n  type = string\n}\n\ndata \"sql\" \"tenants\" {\n  url = var.url\n  query = <<EOS\nSELECT \"schema_name\"\n  FROM \"information_schema\".\"schemata\"\n  WHERE \"schema_name\" LIKE $1\nEOS\n  args = [var.pattern]\n}\n\nenv \"dev\" {\n  for_each = toset(data.sql.tenants.values)\n  url      = urlqueryset(var.url, \"search_path\", each.value)\n}\n\n-- migrations/1_create_users.sql --\nCREATE TABLE \"users\" (\n  \"id\" bigint NOT NULL,\n  PRIMARY KEY (\"id\")\n)\n\n"
  },
  {
    "path": "internal/integration/testdata/postgres/cli-migrate-apply.txtar",
    "content": "! atlas migrate apply\nstderr 'Error: checksum file not found'\nstdout 'You have a checksum error in your migration directory.'\nstdout 'atlas migrate hash'\n\natlas migrate hash\n\n# Apply all of them\natlas migrate apply --url URL --revisions-schema $db\nstdout 'Migrating to version 3 \\(3 migrations in total\\):'\nstdout '-- migrating version 1'\nstdout '-> CREATE TABLE \"users\" \\(\"id\" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, \"age\" bigint NOT NULL, \"name\" character varying NOT NULL, PRIMARY KEY \\(\"id\"\\)\\);'\nstdout '-- migrating version 2'\nstdout '-> CREATE UNIQUE INDEX \"users_age_key\" ON \"users\" \\(\"age\"\\);'\nstdout '-- migrating version 3'\nstdout '-> CREATE TABLE \"pets\" \\(\"id\" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, \"name\" character varying NOT NULL, PRIMARY KEY \\(\"id\"\\)\\);'\nstdout '-- 3 migrations'\nstdout '-- 3 sql statements'\ncmpshow users users.sql\ncmpshow pets pets.sql\n\natlas migrate apply --url URL --revisions-schema $db 1\nstdout 'No migration files to execute'\n\nclearSchema\n\n# Apply one by one\natlas migrate apply --url URL --revisions-schema $db 1\nstdout 'Migrating to version 1 \\(1 migrations in total\\):'\ncmpshow users users_1.sql\n\natlas migrate apply --url URL --revisions-schema $db 1\nstdout 'Migrating to version 2 from 1 \\(1 migrations in total\\):'\ncmpshow users users.sql\n\natlas migrate apply --url URL --revisions-schema $db 1\nstdout 'Migrating to version 3 from 2 \\(1 migrations in total\\):'\ncmpshow users users.sql\ncmpshow pets pets.sql\n\natlas migrate apply --url URL --revisions-schema $db 1\nstdout 'No migration files to execute'\n\nclearSchema\n\n# Move the broken migration into the migrations directory and check the different transaction modes.\ncp broken.sql migrations/4_fourth.sql\natlas migrate hash\n\n! atlas migrate apply --url URL --revisions-schema $db --tx-mode invalid\nstderr 'unknown tx-mode \"invalid\"'\n\n# Test --tx-mode all\n\n! atlas migrate apply --url URL --revisions-schema $db --tx-mode all\nstderr 'executing statement \"THIS IS A FAILING STATEMENT;\" from version \"4\"'\natlas schema inspect --url URL --exclude atlas_schema_revisions\ncmp stdout empty.hcl\n\n# Apply one migration, after rolling everything back, the first revision must still exist.\natlas migrate apply --url URL --revisions-schema $db 1\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users\ncmp stdout empty.hcl\ncmpshow users users_1.sql\n\n! atlas migrate apply --url URL --revisions-schema $db --tx-mode all\nstderr 'executing statement \"THIS IS A FAILING STATEMENT;\" from version \"4\"'\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users\ncmp stdout empty.hcl\n\n# If the broken migration is gone, we can apply everything without any problems.\nrm migrations/4_fourth.sql\natlas migrate hash\n\natlas migrate apply --url URL --revisions-schema $db\ncmpshow users users.sql\ncmpshow pets pets.sql\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets\ncmp stdout empty.hcl\n\nclearSchema\n\n# Test --tx-mode file\n\ncp broken.sql migrations/4_fourth.sql\natlas migrate hash\n\n! atlas migrate apply --url URL --revisions-schema $db --tx-mode file\nstderr 'executing statement \"THIS IS A FAILING STATEMENT;\" from version \"4\"'\natlas schema inspect --url URL --exclude atlas_schema_revisions\ncmpshow users users.sql\ncmpshow pets pets.sql\n\n# Table \"broken\" does not exist since we rolled back that migration.\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets\ncmp stdout empty.hcl\n\n# If the broken migration is gone, we can apply everything without any problems.\nrm migrations/4_fourth.sql\natlas migrate hash\n\natlas migrate apply --url URL --revisions-schema $db\ncmpshow users users.sql\ncmpshow pets pets.sql\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets\ncmp stdout empty.hcl\n\nclearSchema\n\n# Test --tx-mode none\n\ncp broken.sql migrations/4_fourth.sql\natlas migrate hash\n\n! atlas migrate apply --url URL --revisions-schema $db --tx-mode none\nstderr 'executing statement \"THIS IS A FAILING STATEMENT;\" from version \"4\"'\natlas schema inspect --url URL --exclude atlas_schema_revisions\ncmpshow users users.sql\ncmpshow pets pets.sql\n\n# Table \"broken\" does exist since we do not have transactions.\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets\ncmp stdout broken.hcl\n\n-- migrations/1_first.sql --\nCREATE TABLE \"users\" (\"id\" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, \"age\" bigint NOT NULL, \"name\" character varying NOT NULL, PRIMARY KEY (\"id\"));\n\n-- migrations/2_second.sql --\nCREATE UNIQUE INDEX \"users_age_key\" ON \"users\" (\"age\");\n\n-- migrations/3_third.sql --\nCREATE TABLE \"pets\" (\"id\" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, \"name\" character varying NOT NULL, PRIMARY KEY (\"id\"));\n\n-- broken.sql --\nCREATE TABLE \"broken\" (\"id\" bigint);\nTHIS IS A FAILING STATEMENT;\n\n-- empty.hcl --\nschema \"script_cli_migrate_apply\" {\n}\n-- broken.hcl --\ntable \"broken\" {\n  schema = schema.script_cli_migrate_apply\n  column \"id\" {\n    null = true\n    type = bigint\n  }\n}\nschema \"script_cli_migrate_apply\" {\n}\n-- users.sql --\n                        Table \"script_cli_migrate_apply.users\"\n Column |       Type        | Collation | Nullable |             Default\n--------+-------------------+-----------+----------+----------------------------------\n id     | bigint            |           | not null | generated by default as identity\n age    | bigint            |           | not null |\n name   | character varying |           | not null |\nIndexes:\n    \"users_pkey\" PRIMARY KEY, btree (id)\n    \"users_age_key\" UNIQUE, btree (age)\n\n-- users_1.sql --\n                        Table \"script_cli_migrate_apply.users\"\n Column |       Type        | Collation | Nullable |             Default\n--------+-------------------+-----------+----------+----------------------------------\n id     | bigint            |           | not null | generated by default as identity\n age    | bigint            |           | not null |\n name   | character varying |           | not null |\nIndexes:\n    \"users_pkey\" PRIMARY KEY, btree (id)\n\n-- pets.sql --\n                        Table \"script_cli_migrate_apply.pets\"\n Column |       Type        | Collation | Nullable |             Default\n--------+-------------------+-----------+----------+----------------------------------\n id     | bigint            |           | not null | generated by default as identity\n name   | character varying |           | not null |\nIndexes:\n    \"pets_pkey\" PRIMARY KEY, btree (id)\n"
  },
  {
    "path": "internal/integration/testdata/postgres/cli-migrate-diff-unsupported.txtar",
    "content": "atlas migrate hash\natlas migrate diff --dev-url URL --to file://./schema.hcl\ncmpmig 1 2.expected.sql\n\n# Test no diff.\natlas migrate diff --dev-url URL --to file://./schema.hcl\nstdout 'The migration directory is synced with the desired state, no changes to be made'\n\n-- migrations/1_baseline.sql --\nCREATE OR REPLACE FUNCTION random_id(n INTEGER) RETURNS TEXT AS $$\nDECLARE\n  chars TEXT := '0123456789';\n  result TEXT := '';\n  i INTEGER := 0;\nBEGIN\n  FOR i IN 1..n LOOP\n    result := result || substr(chars, trunc(random()*10)::integer + 1, 1);\n  END LOOP;\n  RETURN result;\nEND;\n$$ LANGUAGE plpgsql;\n\n-- schema.hcl --\nschema \"script_cli_migrate_diff_unsupported\" {}\n\ntable \"users\" {\n  schema = schema.script_cli_migrate_diff_unsupported\n  column \"id\" {\n    null = false\n    type = text\n    default = sql(\"random_id(10)\")\n  }\n}\n\n-- 2.expected.sql --\n-- Create \"users\" table\nCREATE TABLE \"users\" (\"id\" text NOT NULL DEFAULT random_id(10));"
  },
  {
    "path": "internal/integration/testdata/postgres/cli-migrate-diff.txtar",
    "content": "exec mkdir migrations\n\n! atlas migrate diff --to file://1.hcl --dir file://migrations\nstderr '\"dev-url\" not set'\n\n! atlas migrate diff --dev-url postgres://devdb --dir file://migrations\nstderr '\"to\" not set'\n\natlas migrate diff --dev-url URL --to file://./1.hcl first\ncmpmig 0 1.sql\n\natlas migrate diff --dev-url URL --to file://./2.hcl second\ncmpmig 1 2.sql\n\n-- 1.hcl --\nschema \"script_cli_migrate_diff\" {}\n\ntable \"users\" {\n  schema = schema.script_cli_migrate_diff\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n}\n\n-- 1.sql --\n-- Create \"users\" table\nCREATE TABLE \"users\" (\"id\" bigint NOT NULL, PRIMARY KEY (\"id\"));\n\n-- 2.hcl --\nschema \"script_cli_migrate_diff\" {}\n\ntable \"users\" {\n  schema = schema.script_cli_migrate_diff\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n  column \"create_time\" {\n    null    = false\n    type    = timestamp(4)\n    default = sql(\"CURRENT_TIMESTAMP(4)\")\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n}\n\n-- 2.sql --\n-- Modify \"users\" table\nALTER TABLE \"users\" ADD COLUMN \"create_time\" timestamp(4) NOT NULL DEFAULT CURRENT_TIMESTAMP(4);"
  },
  {
    "path": "internal/integration/testdata/postgres/cli-migrate-status.txtar",
    "content": "# make sure sum file is correct\natlas migrate hash\n\n# for clean database\natlas migrate status --url URL --revisions-schema $db\ncmp stdout status_clean.txt\n\n# apply one\natlas migrate apply --url URL --revisions-schema $db 1\natlas migrate status --url URL --revisions-schema $db\ncmp stdout status_one_applied.txt\n\n# apply next (and last)\natlas migrate apply --url URL --revisions-schema $db 1\natlas migrate status --url URL --revisions-schema $db\ncmp stdout status_ok.txt\n\n-- migrations/1.sql --\nCREATE TABLE \"users\" (\"id\" bigint NOT NULL GENERATED ALWAYS AS IDENTITY, PRIMARY KEY (\"id\"));\n\n-- migrations/2.sql --\nALTER TABLE \"users\" ADD COLUMN \"happy\" boolean NOT NULL DEFAULT true;\n\n-- broken_migration.sql --\nCREATE TABLE \"users\" (\"id\" bigint NOT NULL GENERATED ALWAYS AS IDENTITY, PRIMARY KEY (\"id\"));\nTHIS LINE ADDS A SYNTAX ERROR;\n\n-- fixed_migration.sql --\nCREATE TABLE \"users\" (\"id\" bigint NOT NULL GENERATED ALWAYS AS IDENTITY, PRIMARY KEY (\"id\"));\nALTER TABLE \"users\" ADD COLUMN \"happy\" boolean NOT NULL DEFAULT true;\n\n-- status_clean.txt --\nMigration Status: PENDING\n  -- Current Version: No migration applied yet\n  -- Next Version:    1\n  -- Executed Files:  0\n  -- Pending Files:   2\n-- status_one_applied.txt --\nMigration Status: PENDING\n  -- Current Version: 1\n  -- Next Version:    2\n  -- Executed Files:  1\n  -- Pending Files:   1\n-- status_ok.txt --\nMigration Status: OK\n  -- Current Version: 2\n  -- Next Version:    Already at latest version\n  -- Executed Files:  2\n  -- Pending Files:   0"
  },
  {
    "path": "internal/integration/testdata/postgres/column-array.txtar",
    "content": "apply 1.hcl\ncmpshow logs 1.sql\n\n# Change size of the underlying type.\napply 2.change-size.hcl\ncmpshow logs 2.sql\n\nsynced 3.nochange.hcl\nsynced 4.nochange.hcl\n\napply 5.hcl\ncmpshow logs 5.sql\n\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"logs\" {\n  schema    = schema.$db\n  column \"records\" {\n    null      = false\n    type      = sql(\"varchar(255)[]\")\n  }\n}\n\n-- 1.sql --\n                  Table \"script_column_array.logs\"\n Column  |           Type           | Collation | Nullable | Default\n---------+--------------------------+-----------+----------+---------\n records | character varying(255)[] |           | not null |\n\n\n-- 2.change-size.hcl --\nschema \"$db\" {}\n\ntable \"logs\" {\n  schema    = schema.$db\n  column \"records\" {\n    null      = false\n    type      = sql(\"varchar(100) ARRAY\")\n  }\n}\n\n-- 2.sql --\n                  Table \"script_column_array.logs\"\n Column  |           Type           | Collation | Nullable | Default\n---------+--------------------------+-----------+----------+---------\n records | character varying(100)[] |           | not null |\n\n-- 3.nochange.hcl --\nschema \"$db\" {}\n\ntable \"logs\" {\n  schema    = schema.$db\n  column \"records\" {\n    null      = false\n    type      = sql(\"varchar(100) ARRAY\")\n  }\n}\n\n-- 4.nochange.hcl --\nschema \"$db\" {}\n\ntable \"logs\" {\n  schema    = schema.$db\n  column \"records\" {\n    null      = false\n    type      = sql(\"varchar(100) [10][]\")\n  }\n}\n\n-- 5.hcl --\nschema \"$db\" {}\n\ntable \"logs\" {\n  schema    = schema.$db\n  column \"a\" {\n    null = false\n    type = sql(\"int[1]\")\n  }\n  column \"b\" {\n    null = false\n    type = sql(\"int ARRAY[1]\")\n  }\n  column \"c\" {\n    null = false\n    type = sql(\"character varying(100) ARRAY[1]\")\n  }\n  column \"d\" {\n    null = false\n    type = sql(\"point [][1]\")\n  }\n}\n\n-- 5.sql --\n       Table \"script_column_array.logs\"\n Column |           Type           | Collation | Nullable | Default\n--------+--------------------------+-----------+----------+---------\n a      | integer[]                |           | not null |\n b      | integer[]                |           | not null |\n c      | character varying(100)[] |           | not null |\n d      | point[]                  |           | not null |\n\n"
  },
  {
    "path": "internal/integration/testdata/postgres/column-bit.txtar",
    "content": "apply 1.hcl\ncmpshow t 1.sql\n\n# Change size of the underlying type.\napply 2.hcl\ncmpshow t 2.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"t\" {\n  schema = schema.$db\n  column \"c1\" {\n    // Equals to bit(1).\n    type = bit\n  }\n  column \"c2\" {\n    type = bit(2)\n  }\n  column \"c3\" {\n    // Unlimited length.\n    type = bit_varying\n  }\n  column \"c4\" {\n    type = bit_varying(1)\n  }\n}\n\n-- 1.sql --\n               Table \"script_column_bit.t\"\n Column |      Type      | Collation | Nullable | Default\n--------+----------------+-----------+----------+---------\n c1     | bit(1)         |           | not null |\n c2     | bit(2)         |           | not null |\n c3     | bit varying    |           | not null |\n c4     | bit varying(1) |           | not null |\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"t\" {\n  schema = schema.$db\n  column \"c1\" {\n    // No change.\n    type = bit(1)\n  }\n  column \"c2\" {\n    // Reduce size.\n    type = bit(1)\n  }\n  column \"c3\" {\n    // Add size.\n    type = bit_varying(4)\n  }\n  column \"c4\" {\n    // Increase size.\n    type = bit_varying(64)\n  }\n}\n\n-- 2.sql --\n               Table \"script_column_bit.t\"\n Column |      Type       | Collation | Nullable | Default\n--------+-----------------+-----------+----------+---------\n c1     | bit(1)          |           | not null |\n c2     | bit(1)          |           | not null |\n c3     | bit varying(4)  |           | not null |\n c4     | bit varying(64) |           | not null |\n\n"
  },
  {
    "path": "internal/integration/testdata/postgres/column-comment.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"created_at\" {\n    null = false\n    type = timestamp\n    comment = \"without time zone\"\n  }\n}\n\n-- 1.sql --\n                   Table \"script_column_comment.users\"\n   Column   |            Type             | Collation | Nullable | Default\n------------+-----------------------------+-----------+----------+---------\n created_at | timestamp without time zone |           | not null |\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"created_at\" {\n    null = false\n    type = timestamptz\n    comment = \"with time zone\"\n  }\n}\n\n-- 2.sql --\n                 Table \"script_column_comment.users\"\n   Column   |           Type           | Collation | Nullable | Default\n------------+--------------------------+-----------+----------+---------\n created_at | timestamp with time zone |           | not null |\n\n"
  },
  {
    "path": "internal/integration/testdata/postgres/column-default.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\natlas schema inspect -u URL > got\ncmp 1.inspected.hcl got\n\n# Change column default.\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    type = character_varying\n    default = \"unknown\"\n  }\n  column \"age\" {\n    type = int\n    default = 1\n  }\n  column \"active\" {\n    type = boolean\n    default = true\n  }\n  column \"bpchar\" {\n    type = bpchar\n    default = \"foo\"\n  }\n}\n\n-- 1.inspected.hcl --\ntable \"users\" {\n  schema = schema.script_column_default\n  column \"name\" {\n    null    = false\n    type    = character_varying\n    default = \"unknown\"\n  }\n  column \"age\" {\n    null    = false\n    type    = integer\n    default = 1\n  }\n  column \"active\" {\n    null    = false\n    type    = boolean\n    default = true\n  }\n  column \"bpchar\" {\n    null    = false\n    type    = bpchar\n    default = \"foo\"\n  }\n}\nschema \"script_column_default\" {\n}\n-- 1.sql --\n                       Table \"script_column_default.users\"\n Column |       Type        | Collation | Nullable |           Default\n--------+-------------------+-----------+----------+------------------------------\n name   | character varying |           | not null | 'unknown'::character varying\n age    | integer           |           | not null | 1\n active | boolean           |           | not null | true\n bpchar | bpchar            |           | not null | 'foo'::bpchar\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    type = character_varying\n    default = \"anonymous\"\n  }\n  column \"age\" {\n    type = int\n    default = 0\n  }\n  column \"active\" {\n    type = boolean\n    default = false\n  }\n}\n\n-- 2.sql --\n                        Table \"script_column_default.users\"\n Column |       Type        | Collation | Nullable |            Default\n--------+-------------------+-----------+----------+--------------------------------\n name   | character varying |           | not null | 'anonymous'::character varying\n age    | integer           |           | not null | 0\n active | boolean           |           | not null | false\n\n"
  },
  {
    "path": "internal/integration/testdata/postgres/column-domain.txtar",
    "content": "execsql 'CREATE DOMAIN script_column_domain.positive_int AS bigint CHECK (VALUE > 0)'\n\napply 1.hcl\ncmpshow users 1.sql\ncmphcl 1.inspect.hcl\n\n-- 1.hcl --\nschema \"script_column_domain\" {}\n\ntable \"users\" {\n  schema = schema.script_column_domain\n  column \"c1\" {\n    type = sql(\"script_column_domain.positive_int\")\n  }\n}\n\n-- 1.sql --\n                     Table \"script_column_domain.users\"\n Column |               Type                | Collation | Nullable | Default\n--------+-----------------------------------+-----------+----------+---------\n c1     | script_column_domain.positive_int |           | not null |\n\n-- 1.inspect.hcl --\ntable \"users\" {\n  schema = schema.script_column_domain\n  column \"c1\" {\n    null = false\n    type = sql(\"positive_int\")\n  }\n}\nschema \"script_column_domain\" {\n}"
  },
  {
    "path": "internal/integration/testdata/postgres/column-enum-array.txtar",
    "content": "# Create table with an enum array column.\napply 1.hcl\ncmpshow enums 1.sql\n\n# Drop an enum array column.\napply 2.hcl\ncmpshow enums 2.sql\n\n# Append an enum array column to an existing table.\napply 3.hcl\ncmpshow enums 3.sql\n\n# Append an enum column to existing enum.\napply 4.hcl\ncmpshow enums 4.sql\n\n# Append an enum value.\napply 5.hcl\ncmphcl 5.inspect.hcl\n\n-- 1.hcl --\nschema \"$db\" {}\n\nenum \"status\" {\n    schema = schema.$db\n    values = [\"active\", \"inactive\"]\n}\n\ntable \"enums\" {\n  schema = schema.$db\n  column \"statuses\" {\n    type = sql(\"status[]\")\n  }\n}\n\n-- 1.sql --\n                    Table \"script_column_enum_array.enums\"\n  Column  |               Type                | Collation | Nullable | Default\n----------+-----------------------------------+-----------+----------+---------\n statuses | script_column_enum_array.status[] |           | not null |\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"enums\" {\n  schema = schema.$db\n  column \"a\" {\n    type = int\n  }\n}\n\n-- 2.sql --\n      Table \"script_column_enum_array.enums\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n a      | integer |           | not null |\n\n-- 3.hcl --\nschema \"$db\" {}\n\nenum \"status\" {\n    schema = schema.$db\n    values = [\"active\", \"inactive\"]\n}\n\ntable \"enums\" {\n  schema = schema.$db\n  column \"a\" {\n    type = int\n  }\n  column \"statuses\" {\n    type = sql(\"status[]\")\n  }\n}\n\n-- 3.sql --\n                    Table \"script_column_enum_array.enums\"\n  Column  |               Type                | Collation | Nullable | Default\n----------+-----------------------------------+-----------+----------+---------\n a        | integer                           |           | not null |\n statuses | script_column_enum_array.status[] |           | not null |\n\n-- 4.hcl --\nschema \"$db\" {}\n\nenum \"status\" {\n    schema = schema.$db\n    values = [\"active\", \"inactive\"]\n}\n\ntable \"enums\" {\n  schema = schema.$db\n  column \"a\" {\n    type = int\n  }\n  column \"statuses\" {\n    type = sql(\"status[]\")\n  }\n  column \"status\" {\n    type = enum.status\n  }\n}\n\n-- 4.sql --\n                    Table \"script_column_enum_array.enums\"\n  Column  |               Type                | Collation | Nullable | Default\n----------+-----------------------------------+-----------+----------+---------\n a        | integer                           |           | not null |\n statuses | script_column_enum_array.status[] |           | not null |\n status   | script_column_enum_array.status   |           | not null |\n\n\n-- 5.hcl --\nschema \"$db\" {}\n\nenum \"status\" {\n    schema = schema.$db\n    values = [\"active\", \"inactive\", \"unknown\"]\n}\n\ntable \"enums\" {\n  schema = schema.$db\n  column \"a\" {\n    type = int\n  }\n  column \"statuses\" {\n    type = sql(\"status[]\")\n  }\n  column \"status\" {\n    type = enum.status\n  }\n}\n\n-- 5.inspect.hcl --\ntable \"enums\" {\n  schema = schema.script_column_enum_array\n  column \"a\" {\n    null = false\n    type = integer\n  }\n  column \"statuses\" {\n    null = false\n    type = sql(\"status[]\")\n  }\n  column \"status\" {\n    null = false\n    type = enum.status\n  }\n}\nenum \"status\" {\n  schema = schema.script_column_enum_array\n  values = [\"active\", \"inactive\", \"unknown\"]\n}\nschema \"script_column_enum_array\" {\n}\n"
  },
  {
    "path": "internal/integration/testdata/postgres/column-enum.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\napply 2.hcl\ncmpshow users 2.sql\n\n# Drop the enum.\napply 3.hcl\ncmpshow users 3.sql\n\n# Add it back.\napply 2.hcl\ncmpshow users 2.sql\n\n# Test schema output.\natlas schema inspect -u URL --format '{{ sql . \"  \" }}' > got.sql\ncmp got.sql want.sql\n\n# Rename the column.\napply 4.hcl\ncmpshow users 4.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\nenum \"status\" {\n    schema = schema.$db\n    values = [\"active\", \"inactive\"]\n}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"type\" {\n    type = enum.status\n    default = \"active\"\n  }\n}\n\n-- 1.sql --\n                          Table \"script_column_enum.users\"\n Column |           Type            | Collation | Nullable |               Default\n--------+---------------------------+-----------+----------+-------------------------------------\n type   | script_column_enum.status |           | not null | 'active'::script_column_enum.status\n\n\n-- 2.hcl --\nschema \"$db\" {}\n\nenum \"status\" {\n  schema = schema.$db\n  values = [\"active\", \"inactive\"]\n}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"type\" {\n    type = enum.status\n    default = \"inactive\"\n  }\n}\n\n-- 2.sql --\n                                 Table \"script_column_enum.users\"\n Column |           Type            | Collation | Nullable |                Default\n--------+---------------------------+-----------+----------+---------------------------------------\n type   | script_column_enum.status |           | not null | 'inactive'::script_column_enum.status\n\n-- 3.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"int\" {\n    type = int\n    default = 1\n  }\n}\n\n-- 3.sql --\n         Table \"script_column_enum.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n int    | integer |           | not null | 1\n\n-- want.sql --\n-- Create enum type \"status\"\nCREATE TYPE \"status\" AS ENUM ('active', 'inactive');\n-- Create \"users\" table\nCREATE TABLE \"users\" (\n  \"type\" \"status\" NOT NULL DEFAULT 'inactive'\n);\n-- 4.hcl --\nschema \"$db\" {}\n\nenum \"status\" {\n  schema = schema.$db\n  values = [\"active\", \"inactive\"]\n}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"renamed\" {\n    type = enum.status\n    default = \"inactive\"\n  }\n}\n\n-- 4.sql --\n                                  Table \"script_column_enum.users\"\n Column  |           Type            | Collation | Nullable |                Default\n---------+---------------------------+-----------+----------+---------------------------------------\n renamed | script_column_enum.status |           | not null | 'inactive'::script_column_enum.status"
  },
  {
    "path": "internal/integration/testdata/postgres/column-float.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"c1\" {\n    type = real\n  }\n  column \"c2\" {\n    type = double_precision\n  }\n  column \"c3\" {\n    // Equals to real when precision is between 1 and 24.\n    type = float(10)\n  }\n  column \"c4\" {\n    // Equals to double_precision when precision is between 1 and 24.\n    type = float(30)\n  }\n}\n\n-- 1.sql --\n             Table \"script_column_float.users\"\n Column |       Type       | Collation | Nullable | Default\n--------+------------------+-----------+----------+---------\n c1     | real             |           | not null |\n c2     | double precision |           | not null |\n c3     | real             |           | not null |\n c4     | double precision |           | not null |\n\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"c1\" {\n    type = double_precision\n  }\n  column \"c2\" {\n    type = real\n  }\n  column \"c3\" {\n    type = float(30)\n  }\n  column \"c4\" {\n    type = float(10)\n  }\n}\n\n-- 2.sql --\n             Table \"script_column_float.users\"\n Column |       Type       | Collation | Nullable | Default\n--------+------------------+-----------+----------+---------\n c1     | double precision |           | not null |\n c2     | real             |           | not null |\n c3     | double precision |           | not null |\n c4     | real             |           | not null |"
  },
  {
    "path": "internal/integration/testdata/postgres/column-generated-inspect.txtar",
    "content": "# Skip PostgreSQL 10, 11 as they do not support generated columns.\n! only postgres10|postgres11\n\napply 1.hcl\ncmphcl 1.inspect.hcl\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"a\" {\n        type = int\n    }\n    column \"b\" {\n        type = int\n        as = \"1\"\n    }\n    column \"c\" {\n        type = int\n        as {\n            expr = \"2\"\n            type = STORED\n        }\n    }\n}\n\n-- 1.inspect.hcl --\ntable \"users\" {\n  schema = schema.$db\n  column \"a\" {\n    null = false\n    type = integer\n  }\n  column \"b\" {\n    null = false\n    type = integer\n    as {\n      expr = \"1\"\n      type = STORED\n    }\n  }\n  column \"c\" {\n    null = false\n    type = integer\n    as {\n      expr = \"2\"\n      type = STORED\n    }\n  }\n}\nschema \"$db\" {\n}\n"
  },
  {
    "path": "internal/integration/testdata/postgres/column-identity.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\n# Change identity generation.\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = int\n    identity {\n        generated = ALWAYS\n        start = 10\n        increment = 10\n    }\n  }\n}\n\n-- 1.sql --\n                  Table \"script_column_identity.users\"\n Column |  Type   | Collation | Nullable |           Default\n--------+---------+-----------+----------+------------------------------\n name   | integer |           | not null | generated always as identity\n\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = int\n    identity {\n        generated = BY_DEFAULT\n        start = 10\n        increment = 10\n    }\n  }\n}\n\n-- 2.sql --\n                    Table \"script_column_identity.users\"\n Column |  Type   | Collation | Nullable |             Default\n--------+---------+-----------+----------+----------------------------------\n name   | integer |           | not null | generated by default as identity"
  },
  {
    "path": "internal/integration/testdata/postgres/column-interval.txtar",
    "content": "apply 1.hcl\ncmpshow logs 1.sql\ncmphcl 1.inspect.hcl\n\n-- 1.hcl --\ntable \"logs\" {\n  schema = schema.script_column_interval\n  column \"a\" {\n    null = false\n    type = interval\n    default = \"3 hours\"\n  }\n  column \"b\" {\n    null = false\n    type = interval(1)\n  }\n  column \"c\" {\n    null = false\n    type = second\n  }\n  column \"d\" {\n    null = false\n    type = second(1)\n  }\n  column \"e\" {\n    null = true\n    type = day_to_second(4)\n  }\n}\n\nschema \"script_column_interval\" {}\n\n-- 1.sql --\n                 Table \"script_column_interval.logs\"\n Column |           Type            | Collation | Nullable |       Default\n--------+---------------------------+-----------+----------+----------------------\n a      | interval                  |           | not null | '03:00:00'::interval\n b      | interval(1)               |           | not null |\n c      | interval second           |           | not null |\n d      | interval second(1)        |           | not null |\n e      | interval day to second(4) |           |          |\n\n\n-- 1.inspect.hcl --\ntable \"logs\" {\n  schema = schema.script_column_interval\n  column \"a\" {\n    null    = false\n    type    = interval\n    default = sql(\"'03:00:00'::interval\")\n  }\n  column \"b\" {\n    null = false\n    type = interval(1)\n  }\n  column \"c\" {\n    null = false\n    type = second\n  }\n  column \"d\" {\n    null = false\n    type = second(1)\n  }\n  column \"e\" {\n    null = true\n    type = day_to_second(4)\n  }\n}\nschema \"script_column_interval\" {\n}"
  },
  {
    "path": "internal/integration/testdata/postgres/column-numeric.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"a\" {\n    null = false\n    type = numeric\n  }\n  column \"b\" {\n    null = false\n    type = numeric(10)\n  }\n  column \"c\" {\n    null = false\n    type = numeric(10,2)\n  }\n  column \"d\" {\n    null = false\n    type = decimal\n  }\n  column \"e\" {\n    null = false\n    type = decimal(10)\n  }\n  column \"f\" {\n    null = false\n    type = decimal(10,2)\n  }\n}\n\n-- 1.sql --\n           Table \"script_column_numeric.users\"\n Column |     Type      | Collation | Nullable | Default\n--------+---------------+-----------+----------+---------\n a      | numeric       |           | not null |\n b      | numeric(10,0) |           | not null |\n c      | numeric(10,2) |           | not null |\n d      | numeric       |           | not null |\n e      | numeric(10,0) |           | not null |\n f      | numeric(10,2) |           | not null |\n\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"a\" {\n    null = false\n    type = numeric(5)\n  }\n  column \"b\" {\n    null = false\n    type = numeric(10,2)\n  }\n  column \"c\" {\n    null = false\n    type = numeric\n  }\n  column \"d\" {\n    null = false\n    type = decimal(4)\n  }\n  column \"e\" {\n    null = false\n    type = decimal\n  }\n  column \"f\" {\n    null = false\n    type = decimal(10,3)\n  }\n}\n\n-- 2.sql --\n           Table \"script_column_numeric.users\"\n Column |     Type      | Collation | Nullable | Default\n--------+---------------+-----------+----------+---------\n a      | numeric(5,0)  |           | not null |\n b      | numeric(10,2) |           | not null |\n c      | numeric       |           | not null |\n d      | numeric(4,0)  |           | not null |\n e      | numeric       |           | not null |\n f      | numeric(10,3) |           | not null |"
  },
  {
    "path": "internal/integration/testdata/postgres/column-range.txtar",
    "content": "only postgres14 postgres15\n\napply 1.hcl\ncmpshow t 1.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"t\" {\n  schema = schema.$db\n  column \"r1\" {\n    type = int4range\n  }\n  column \"r2\" {\n    type = int8range\n  }\n  column \"r3\" {\n    type = numrange\n  }\n  column \"r4\" {\n    type = tsrange\n  }\n  column \"r5\" {\n    type = tstzrange\n  }\n  column \"r6\" {\n    type = daterange\n  }\n  column \"r7\" {\n    type = int4multirange\n  }\n  column \"r8\" {\n    type = int8multirange\n  }\n  column \"r9\" {\n    type = nummultirange\n  }\n  column \"r10\" {\n    type = tsmultirange\n  }\n  column \"r11\" {\n    type = tstzmultirange\n  }\n  column \"r12\" {\n    type = datemultirange\n  }\n}\n\n-- 1.sql --\n            Table \"script_column_range.t\"\n Column |      Type      | Collation | Nullable | Default\n--------+----------------+-----------+----------+---------\n r1     | int4range      |           | not null |\n r2     | int8range      |           | not null |\n r3     | numrange       |           | not null |\n r4     | tsrange        |           | not null |\n r5     | tstzrange      |           | not null |\n r6     | daterange      |           | not null |\n r7     | int4multirange |           | not null |\n r8     | int8multirange |           | not null |\n r9     | nummultirange  |           | not null |\n r10    | tsmultirange   |           | not null |\n r11    | tstzmultirange |           | not null |\n r12    | datemultirange |           | not null |\n"
  },
  {
    "path": "internal/integration/testdata/postgres/column-serial.txtar",
    "content": "apply 1.hcl\ncmpshow t 1.sql\n\napply 2.hcl\ncmpshow t 2.sql\n\napply 3.hcl\ncmpshow t 3.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"t\" {\n  schema = schema.$db\n  column \"x\" {\n    type = smallserial\n  }\n  column \"y\" {\n    type = serial\n  }\n  column \"z\" {\n    type = bigserial\n  }\n}\n\n-- 1.sql --\n                                Table \"script_column_serial.t\"\n Column |   Type   | Collation | Nullable |                      Default\n--------+----------+-----------+----------+---------------------------------------------------\n x      | smallint |           | not null | nextval('script_column_serial.t_x_seq'::regclass)\n y      | integer  |           | not null | nextval('script_column_serial.t_y_seq'::regclass)\n z      | bigint   |           | not null | nextval('script_column_serial.t_z_seq'::regclass)\n\n-- 2.hcl --\n schema \"$db\" {}\n\n table \"t\" {\n   schema = schema.$db\n   column \"x\" {\n     # Drop sequence.\n     type = smallint\n   }\n   column \"y\" {\n     # Drop sequence and change type.\n     type = bigint\n   }\n   column \"z\" {\n     # Change sequence type.\n     type = serial\n   }\n }\n\n-- 2.sql --\n                                Table \"script_column_serial.t\"\n Column |   Type   | Collation | Nullable |                      Default\n--------+----------+-----------+----------+---------------------------------------------------\n x      | smallint |           | not null |\n y      | bigint   |           | not null |\n z      | integer  |           | not null | nextval('script_column_serial.t_z_seq'::regclass)\n\n\n-- 3.hcl --\n schema \"$db\" {}\n\n table \"t\" {\n   schema = schema.$db\n   column \"x\" {\n     # Add sequence.\n     type = smallserial\n   }\n   column \"y\" {\n     # Add sequence and change type.\n     type = serial\n   }\n }\n\n-- 3.sql --\n                                Table \"script_column_serial.t\"\n Column |   Type   | Collation | Nullable |                      Default\n--------+----------+-----------+----------+---------------------------------------------------\n x      | smallint |           | not null | nextval('script_column_serial.t_x_seq'::regclass)\n y      | integer  |           | not null | nextval('script_column_serial.t_y_seq'::regclass)\n"
  },
  {
    "path": "internal/integration/testdata/postgres/column-textsearch.txtar",
    "content": "apply 1.hcl\ncmpshow t 1.sql\ncmphcl 1.inspect.hcl\n\n-- 1.hcl --\nschema \"script_column_textsearch\" {}\n\ntable \"t\" {\n  schema = schema.script_column_textsearch\n  column \"tsv\" {\n    type = tsvector\n  }\n  column \"tsq\" {\n    type = tsquery\n  }\n  index \"idx_tsv\" {\n    type = GIN\n    columns = [column.tsv]\n  }\n}\n\n-- 1.sql --\n         Table \"script_column_textsearch.t\"\n Column |   Type   | Collation | Nullable | Default\n--------+----------+-----------+----------+---------\n tsv    | tsvector |           | not null |\n tsq    | tsquery  |           | not null |\nIndexes:\n    \"idx_tsv\" gin (tsv)\n\n\n-- 1.inspect.hcl --\ntable \"t\" {\n  schema = schema.script_column_textsearch\n  column \"tsv\" {\n    null = false\n    type = tsvector\n  }\n  column \"tsq\" {\n    null = false\n    type = tsquery\n  }\n  index \"idx_tsv\" {\n    columns = [column.tsv]\n    type    = GIN\n  }\n}\nschema \"script_column_textsearch\" {\n}"
  },
  {
    "path": "internal/integration/testdata/postgres/column-time-precision.txtar",
    "content": "# Apply schema \"1.hcl\" on fresh database.\napply 1.hcl\n\n# Compare the result of \"\\d tbl\" with the content of a file named '1.sql'.\ncmpshow tbl 1.sql\n\napply 2.hcl\ncmpshow tbl 2.sql\n\n# Files\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"tbl\" {\n  schema    = schema.$db\n  column \"precision_default\" {\n    null      = false\n    type      = timestamp\n    default   = sql(\"CURRENT_TIMESTAMP\")\n  }\n  column \"timestamp_4\" {\n    null    = false\n    type    = timestamp(4)\n    default = sql(\"CURRENT_TIMESTAMP(4)\")\n  }\n  column \"timestamptz_4\" {\n    null    = false\n    type    = timestamptz(4)\n    default = sql(\"CURRENT_TIMESTAMP(4)\")\n  }\n}\n\n-- 1.sql --\n                           Table \"script_column_time_precision.tbl\"\n      Column       |              Type              | Collation | Nullable |       Default\n-------------------+--------------------------------+-----------+----------+----------------------\n precision_default | timestamp without time zone    |           | not null | CURRENT_TIMESTAMP\n timestamp_4       | timestamp(4) without time zone |           | not null | CURRENT_TIMESTAMP(4)\n timestamptz_4     | timestamp(4) with time zone    |           | not null | CURRENT_TIMESTAMP(4)\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"tbl\" {\n  schema = schema.$db\n  column \"c1\" {\n    type = timestamptz(1)\n  }\n  column \"c2\" {\n    type = timestamptz\n  }\n  column \"c3\" {\n    type = timestamptz(0)\n  }\n  column \"c4\" {\n    type = time\n  }\n  column \"c5\" {\n    type = time(1)\n  }\n  column \"c6\" {\n    type = timestamp\n  }\n  column \"c7\" {\n    type = timestamp(5)\n  }\n  column \"c8\" {\n    type = timetz(0)\n  }\n  column \"c9\" {\n    type = timetz\n  }\n  column \"c10\" {\n    type = timetz(6)\n  }\n}\n\n-- 2.sql --\n                 Table \"script_column_time_precision.tbl\"\n Column |              Type              | Collation | Nullable | Default\n--------+--------------------------------+-----------+----------+---------\n c1     | timestamp(1) with time zone    |           | not null |\n c2     | timestamp with time zone       |           | not null |\n c3     | timestamp(0) with time zone    |           | not null |\n c4     | time without time zone         |           | not null |\n c5     | time(1) without time zone      |           | not null |\n c6     | timestamp without time zone    |           | not null |\n c7     | timestamp(5) without time zone |           | not null |\n c8     | time(0) with time zone         |           | not null |\n c9     | time with time zone            |           | not null |\n c10    | time with time zone            |           | not null |\n"
  },
  {
    "path": "internal/integration/testdata/postgres/foreign-key-action.txtar",
    "content": "apply 1.hcl\ncmpshow table_a table_a.sql\ncmpshow table_b table_b.sql\ncmpshow table_c table_c.sql\ncmphcl 1.inspect.hcl\n\n-- 1.hcl --\nschema \"script_foreign_key_action\" {}\n\ntable \"table_a\" {\n  schema = schema.script_foreign_key_action\n  column \"id\" {\n    type = text\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\n\ntable \"table_b\" {\n  schema = schema.script_foreign_key_action\n  column \"id\" {\n    type = text\n  }\n  column \"table_a_id\" {\n    type = text\n  }\n  primary_key {\n    columns = [column.id]\n  }\n  foreign_key \"table_a_fk\" {\n    columns     = [column.table_a_id]\n    ref_columns = [table.table_a.column.id]\n    on_delete   = \"CASCADE\"\n    on_update   = \"CASCADE\"\n  }\n}\n\ntable \"table_c\" {\n  schema = schema.script_foreign_key_action\n  column \"id\" {\n    type = text\n  }\n  column \"table_a_id\" {\n    type = text\n  }\n  primary_key {\n    columns = [column.id]\n  }\n  foreign_key \"table_a_fk\" {\n    columns     = [column.table_a_id]\n    ref_columns = [table.table_a.column.id]\n  }\n}\n\n-- table_a.sql --\n   Table \"script_foreign_key_action.table_a\"\n Column | Type | Collation | Nullable | Default\n--------+------+-----------+----------+---------\n id     | text |           | not null |\nIndexes:\n    \"table_a_pkey\" PRIMARY KEY, btree (id)\nReferenced by:\n    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\n    TABLE \"script_foreign_key_action.table_c\" CONSTRAINT \"table_a_fk\" FOREIGN KEY (table_a_id) REFERENCES script_foreign_key_action.table_a(id)\n\n-- table_b.sql --\n     Table \"script_foreign_key_action.table_b\"\n   Column   | Type | Collation | Nullable | Default\n------------+------+-----------+----------+---------\n id         | text |           | not null |\n table_a_id | text |           | not null |\nIndexes:\n    \"table_b_pkey\" PRIMARY KEY, btree (id)\nForeign-key constraints:\n    \"table_a_fk\" FOREIGN KEY (table_a_id) REFERENCES script_foreign_key_action.table_a(id) ON UPDATE CASCADE ON DELETE CASCADE\n\n-- table_c.sql --\n     Table \"script_foreign_key_action.table_c\"\n   Column   | Type | Collation | Nullable | Default\n------------+------+-----------+----------+---------\n id         | text |           | not null |\n table_a_id | text |           | not null |\nIndexes:\n    \"table_c_pkey\" PRIMARY KEY, btree (id)\nForeign-key constraints:\n    \"table_a_fk\" FOREIGN KEY (table_a_id) REFERENCES script_foreign_key_action.table_a(id)\n\n-- 1.inspect.hcl --\ntable \"table_a\" {\n  schema = schema.script_foreign_key_action\n  column \"id\" {\n    null = false\n    type = text\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\ntable \"table_b\" {\n  schema = schema.script_foreign_key_action\n  column \"id\" {\n    null = false\n    type = text\n  }\n  column \"table_a_id\" {\n    null = false\n    type = text\n  }\n  primary_key {\n    columns = [column.id]\n  }\n  foreign_key \"table_a_fk\" {\n    columns     = [column.table_a_id]\n    ref_columns = [table.table_a.column.id]\n    on_update   = CASCADE\n    on_delete   = CASCADE\n  }\n}\ntable \"table_c\" {\n  schema = schema.script_foreign_key_action\n  column \"id\" {\n    null = false\n    type = text\n  }\n  column \"table_a_id\" {\n    null = false\n    type = text\n  }\n  primary_key {\n    columns = [column.id]\n  }\n  foreign_key \"table_a_fk\" {\n    columns     = [column.table_a_id]\n    ref_columns = [table.table_a.column.id]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n}\nschema \"script_foreign_key_action\" {\n}"
  },
  {
    "path": "internal/integration/testdata/postgres/foreign-key.txtar",
    "content": "apply 1.hcl\ncmpshow t1 t1.sql\ncmpshow t2 t2.sql\ncmphcl 1.inspect.hcl\n\n-- 1.hcl --\nschema \"$db\" {}\ntable \"t1\" {\n  schema = schema.$db\n  column \"c1\" {\n    null = false\n    type = integer\n  }\n  column \"c2\" {\n    null = true\n    type = integer\n  }\n  column \"c3\" {\n    null = true\n    type = integer\n  }\n  primary_key {\n    columns = [column.c1]\n  }\n  index \"t1_c2_c3_idx\" {\n    unique  = true\n    columns = [column.c2, column.c3]\n  }\n}\ntable \"t2\" {\n  schema = schema.$db\n  column \"c1\" {\n    null = false\n    type = integer\n  }\n  column \"c2\" {\n    null = true\n    type = integer\n  }\n  column \"c3\" {\n    null = true\n    type = integer\n  }\n  primary_key {\n    columns = [column.c1]\n  }\n  foreign_key \"c2_c3_1\" {\n    columns     = [column.c2, column.c3]\n    ref_columns = [table.t1.column.c2, table.t1.column.c3]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n  foreign_key \"c2_c3_2\" {\n    columns     = [column.c2, column.c3]\n    ref_columns = [table.t1.column.c2, table.t1.column.c3]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n}\n\n-- t1.sql --\n           Table \"script_foreign_key.t1\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n c1     | integer |           | not null |\n c2     | integer |           |          |\n c3     | integer |           |          |\nIndexes:\n    \"t1_pkey\" PRIMARY KEY, btree (c1)\n    \"t1_c2_c3_idx\" UNIQUE, btree (c2, c3)\nReferenced by:\n    TABLE \"script_foreign_key.t2\" CONSTRAINT \"c2_c3_1\" FOREIGN KEY (c2, c3) REFERENCES script_foreign_key.t1(c2, c3)\n    TABLE \"script_foreign_key.t2\" CONSTRAINT \"c2_c3_2\" FOREIGN KEY (c2, c3) REFERENCES script_foreign_key.t1(c2, c3)\n\n-- t2.sql --\n           Table \"script_foreign_key.t2\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n c1     | integer |           | not null |\n c2     | integer |           |          |\n c3     | integer |           |          |\nIndexes:\n    \"t2_pkey\" PRIMARY KEY, btree (c1)\nForeign-key constraints:\n    \"c2_c3_1\" FOREIGN KEY (c2, c3) REFERENCES script_foreign_key.t1(c2, c3)\n    \"c2_c3_2\" FOREIGN KEY (c2, c3) REFERENCES script_foreign_key.t1(c2, c3)\n\n-- 1.inspect.hcl --\ntable \"t1\" {\n  schema = schema.script_foreign_key\n  column \"c1\" {\n    null = false\n    type = integer\n  }\n  column \"c2\" {\n    null = true\n    type = integer\n  }\n  column \"c3\" {\n    null = true\n    type = integer\n  }\n  primary_key {\n    columns = [column.c1]\n  }\n  index \"t1_c2_c3_idx\" {\n    unique  = true\n    columns = [column.c2, column.c3]\n  }\n}\ntable \"t2\" {\n  schema = schema.script_foreign_key\n  column \"c1\" {\n    null = false\n    type = integer\n  }\n  column \"c2\" {\n    null = true\n    type = integer\n  }\n  column \"c3\" {\n    null = true\n    type = integer\n  }\n  primary_key {\n    columns = [column.c1]\n  }\n  foreign_key \"c2_c3_1\" {\n    columns     = [column.c2, column.c3]\n    ref_columns = [table.t1.column.c2, table.t1.column.c3]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n  foreign_key \"c2_c3_2\" {\n    columns     = [column.c2, column.c3]\n    ref_columns = [table.t1.column.c2, table.t1.column.c3]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n}\nschema \"script_foreign_key\" {\n}"
  },
  {
    "path": "internal/integration/testdata/postgres/index-desc.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\n# Drop the \"DESC\" option from the key part.\napply 2.hcl\ncmpshow users 2.sql\n# Use of \"columns\" instead of \"on\" should not trigger a change.\nsynced 2-no-change.hcl\n\napply 3.hcl\ncmpshow users 3.sql\n\napply 4.hcl\ncmpshow users 4.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = int\n    }\n    index \"rank_idx\" {\n        on {\n            desc   = true\n            column = column.rank\n        }\n    }\n}\n\n-- 1.sql --\n          Table \"script_index_desc.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n rank   | integer |           | not null |\nIndexes:\n    \"rank_idx\" btree (rank DESC)\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = int\n    }\n    index \"rank_idx\" {\n        on {\n            column = table.users.column.rank\n        }\n    }\n}\n\n-- 2.sql --\n          Table \"script_index_desc.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n rank   | integer |           | not null |\nIndexes:\n    \"rank_idx\" btree (rank)\n\n\n-- 2-no-change.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = int\n    }\n    index \"rank_idx\" {\n        columns = [\n            table.users.column.rank,\n        ]\n    }\n}\n\n-- 3.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = int\n    }\n    column \"score\" {\n        type = int\n    }\n    index \"rank_score_idx\" {\n        on {\n            column = table.users.column.rank\n        }\n        on {\n            column = table.users.column.score\n            desc = true\n        }\n    }\n}\n\n-- 3.sql --\n          Table \"script_index_desc.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n rank   | integer |           | not null |\n score  | integer |           | not null |\nIndexes:\n    \"rank_score_idx\" btree (rank, score DESC)\n\n\n-- 4.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n    schema = schema.$db\n    column \"rank\" {\n        type = int\n    }\n    column \"score\" {\n        type = int\n    }\n    index \"double_rank_desc_idx\" {\n        on {\n            expr = \"rank * 2\"\n            desc = true\n        }\n    }\n    index \"double_score_desc_idx\" {\n        on {\n            expr = \"score * 2\"\n            desc = true\n        }\n    }\n    index \"double_rank_idx\" {\n        on {\n            expr = \"rank * 2\"\n            desc = false\n        }\n    }\n    index \"double_score_idx\" {\n        on {\n            expr = \"score * 2\"\n            desc = false\n        }\n    }\n}\n\n-- 4.sql --\n      Table \"script_index_desc.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n rank   | integer |           | not null |\n score  | integer |           | not null |\nIndexes:\n    \"double_rank_desc_idx\" btree ((rank * 2) DESC)\n    \"double_rank_idx\" btree ((rank * 2))\n    \"double_score_desc_idx\" btree ((score * 2) DESC)\n    \"double_score_idx\" btree ((score * 2))"
  },
  {
    "path": "internal/integration/testdata/postgres/index-expr.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"first_name\" {\n    null = false\n    type = varchar(128)\n  }\n  column \"last_name\" {\n    null = false\n    type = varchar(128)\n  }\n  index \"full_name\" {\n    on {\n        expr = \"first_name || ' ' || last_name\"\n    }\n  }\n}\n\n-- 1.sql --\n                   Table \"script_index_expr.users\"\n   Column   |          Type          | Collation | Nullable | Default\n------------+------------------------+-----------+----------+---------\n first_name | character varying(128) |           | not null |\n last_name  | character varying(128) |           | not null |\nIndexes:\n    \"full_name\" btree (((first_name::text || ' '::text) || last_name::text))\n\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"first_name\" {\n    null = false\n    type = varchar(128)\n  }\n  column \"last_name\" {\n    null = false\n    type = varchar(128)\n  }\n  index \"full_name\" {\n    on {\n        expr = \"first_name || '''s first name'\"\n    }\n  }\n}\n\n-- 2.sql --\n                   Table \"script_index_expr.users\"\n   Column   |          Type          | Collation | Nullable | Default\n------------+------------------------+-----------+----------+---------\n first_name | character varying(128) |           | not null |\n last_name  | character varying(128) |           | not null |\nIndexes:\n    \"full_name\" btree ((first_name::text || '''s first name'::text))"
  },
  {
    "path": "internal/integration/testdata/postgres/index-include.txtar",
    "content": "! only postgres10\n\n# Create with INCLUDE.\napply 1.hcl\ncmpshow users 1.sql\n\n# Append one column to INCLUDE.\napply 2.hcl\ncmpshow users 2.sql\n\n# Remove one column from INCLUDE.\napply 3.hcl\ncmpshow users 3.sql\n\n# Remove INCLUDE.\napply 4.hcl\ncmpshow users 4.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"active\" {\n    null = true\n    type = boolean\n  }\n  index \"users_name\" {\n    columns = [column.name]\n    where = \"active\"\n    include = [column.active]\n  }\n}\n\n-- 1.sql --\n        Table \"script_index_include.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n name   | text    |           | not null |\n active | boolean |           |          |\nIndexes:\n    \"users_name\" btree (name) INCLUDE (active) WHERE active\n\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"active\" {\n    null = true\n    type = boolean\n  }\n  column \"version\" {\n    null = true\n    type = text\n  }\n  index \"users_name\" {\n    columns = [column.name]\n    where = \"active\"\n    include = [column.active, column.version]\n  }\n}\n\n-- 2.sql --\n      Table \"script_index_include.users\"\n Column  |  Type   | Collation | Nullable | Default\n---------+---------+-----------+----------+---------\n name    | text    |           | not null |\n active  | boolean |           |          |\n version | text    |           |          |\nIndexes:\n    \"users_name\" btree (name) INCLUDE (active, version) WHERE active\n\n-- 3.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"active\" {\n    null = true\n    type = boolean\n  }\n  column \"version\" {\n    null = true\n    type = text\n  }\n  index \"users_name\" {\n    columns = [column.name]\n    where = \"active\"\n    include = [column.version]\n  }\n}\n\n-- 3.sql --\n      Table \"script_index_include.users\"\n Column  |  Type   | Collation | Nullable | Default\n---------+---------+-----------+----------+---------\n name    | text    |           | not null |\n active  | boolean |           |          |\n version | text    |           |          |\nIndexes:\n    \"users_name\" btree (name) INCLUDE (version) WHERE active\n\n-- 4.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"active\" {\n    null = true\n    type = boolean\n  }\n  column \"version\" {\n    null = true\n    type = text\n  }\n  index \"users_name\" {\n    columns = [column.name]\n    where = \"active\"\n  }\n}\n\n-- 4.sql --\n      Table \"script_index_include.users\"\n Column  |  Type   | Collation | Nullable | Default\n---------+---------+-----------+----------+---------\n name    | text    |           | not null |\n active  | boolean |           |          |\n version | text    |           |          |\nIndexes:\n    \"users_name\" btree (name) WHERE active\n"
  },
  {
    "path": "internal/integration/testdata/postgres/index-issue-557.txtar",
    "content": "apply 1.hcl\ncmpshow t1 t2 1.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"t1\" {\n  schema = schema.$db\n  column \"a\" {\n    null = false\n    type = uuid\n  }\n  column \"b\" {\n    null = true\n    type = timestamp(6)\n  }\n  index \"t1_a_b\" {\n    on {\n      column = column.a\n    }\n    on {\n      desc   = true\n      column = column.b\n    }\n    unique = true\n  }\n}\n\ntable \"t2\" {\n  schema = schema.$db\n  column \"a\" {\n    null = false\n    type = uuid\n  }\n  primary_key {\n    columns = [column.a]\n  }\n}\n\n-- 1.sql --\n                   Table \"script_index_issue_557.t1\"\n Column |            Type             | Collation | Nullable | Default\n--------+-----------------------------+-----------+----------+---------\n a      | uuid                        |           | not null |\n b      | timestamp without time zone |           |          |\nIndexes:\n    \"t1_a_b\" UNIQUE, btree (a, b DESC)\n\n\n       Table \"script_index_issue_557.t2\"\n Column | Type | Collation | Nullable | Default\n--------+------+-----------+----------+---------\n a      | uuid |           | not null |\nIndexes:\n    \"t2_pkey\" PRIMARY KEY, btree (a)\n"
  },
  {
    "path": "internal/integration/testdata/postgres/index-nulls-distinct.txtar",
    "content": "only postgres15\n\napply 1.hcl\ncmphcl 1.inspect.hcl\ncmpshow users 1.sql\n\n# Change the nulls_distinct property of the index.\napply 2.hcl\ncmphcl 2.inspect.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"script_index_nulls_distinct\" {}\n\ntable \"users\" {\n  schema = schema.script_index_nulls_distinct\n  column \"c\" {\n    type = int\n  }\n  index \"nulls_not_distinct\" {\n    unique         = true\n    columns        = [column.c]\n    nulls_distinct = false\n  }\n  unique \"nulls_not_distinct2\" {\n    columns        = [column.c]\n    nulls_distinct = false\n  }\n}\n\n-- 1.inspect.hcl --\ntable \"users\" {\n  schema = schema.script_index_nulls_distinct\n  column \"c\" {\n    null = false\n    type = integer\n  }\n  index \"nulls_not_distinct\" {\n    unique         = true\n    columns        = [column.c]\n    nulls_distinct = false\n  }\n  unique \"nulls_not_distinct2\" {\n    columns        = [column.c]\n    nulls_distinct = false\n  }\n}\nschema \"script_index_nulls_distinct\" {\n}\n-- 1.sql --\n     Table \"script_index_nulls_distinct.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n c      | integer |           | not null |\nIndexes:\n    \"nulls_not_distinct\" UNIQUE, btree (c) NULLS NOT DISTINCT\n    \"nulls_not_distinct2\" UNIQUE CONSTRAINT, btree (c) NULLS NOT DISTINCT\n\n-- 2.hcl --\nschema \"script_index_nulls_distinct\" {}\n\ntable \"users\" {\n  schema = schema.script_index_nulls_distinct\n  column \"c\" {\n    type = int\n  }\n  index \"nulls_not_distinct\" {\n    unique  = true\n    columns = [column.c]\n  }\n}\n\n-- 2.inspect.hcl --\ntable \"users\" {\n  schema = schema.script_index_nulls_distinct\n  column \"c\" {\n    null = false\n    type = integer\n  }\n  index \"nulls_not_distinct\" {\n    unique  = true\n    columns = [column.c]\n  }\n}\nschema \"script_index_nulls_distinct\" {\n}\n-- 2.sql --\n     Table \"script_index_nulls_distinct.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n c      | integer |           | not null |\nIndexes:\n    \"nulls_not_distinct\" UNIQUE, btree (c)\n\n"
  },
  {
    "path": "internal/integration/testdata/postgres/index-operator-class.txtar",
    "content": "# Run this test only on 14 because tsvector_ops\n# parameters are not supported in old versions.\nonly postgres14\n\napply 1.hcl\ncmpshow pets 1.sql\n\napply 2.hcl\ncmpshow pets 2.sql\ncmphcl 2.inspect.hcl\n\napply 3.hcl\ncmpshow logs 3.sql\n\napply 4.hcl\ncmpshow tsv 4.sql\n\napply 5.hcl\ncmpshow tsv 5.sql\n\n-- 1.hcl --\nschema \"script_index_operator_class\" {}\n\ntable \"pets\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = char(10)\n  }\n  index \"name_idx1\" {\n    on {\n      column = column.name\n      ops    = bpchar_ops\n    }\n  }\n  index \"name_idx2\" {\n    on {\n      column = column.name\n      // Set a non-default operator class.\n      ops    = bpchar_pattern_ops\n    }\n  }\n}\n\n-- 1.sql --\n        Table \"script_index_operator_class.pets\"\n Column |     Type      | Collation | Nullable | Default\n--------+---------------+-----------+----------+---------\n name   | character(10) |           | not null |\nIndexes:\n    \"name_idx1\" btree (name)\n    \"name_idx2\" btree (name bpchar_pattern_ops)\n\n\n-- 2.hcl --\nschema \"script_index_operator_class\" {}\n\ntable \"pets\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = char(10)\n  }\n  // Flip operator classes.\n  index \"name_idx1\" {\n    on {\n      column = column.name\n      ops    = bpchar_pattern_ops\n    }\n  }\n  index \"name_idx2\" {\n    on {\n      column = column.name\n      ops    = bpchar_ops\n    }\n  }\n}\n\n-- 2.sql --\n        Table \"script_index_operator_class.pets\"\n Column |     Type      | Collation | Nullable | Default\n--------+---------------+-----------+----------+---------\n name   | character(10) |           | not null |\nIndexes:\n    \"name_idx1\" btree (name bpchar_pattern_ops)\n    \"name_idx2\" btree (name)\n\n-- 2.inspect.hcl --\ntable \"pets\" {\n  schema = schema.script_index_operator_class\n  column \"name\" {\n    null = false\n    type = character(10)\n  }\n  index \"name_idx1\" {\n    on {\n      column = column.name\n      ops    = bpchar_pattern_ops\n    }\n  }\n  index \"name_idx2\" {\n    columns = [column.name]\n  }\n}\nschema \"script_index_operator_class\" {\n}\n\n-- 3.hcl --\nschema \"script_index_operator_class\" {}\n\ntable \"logs\" {\n  schema = schema.$db\n  column \"j\" {\n    null = false\n    type = jsonb\n  }\n  index \"j_idx\" {\n    type = GIN\n    on {\n      column = column.j\n      ops    = jsonb_path_ops\n    }\n  }\n}\n\n-- 3.sql --\n  Table \"script_index_operator_class.logs\"\n Column | Type  | Collation | Nullable | Default\n--------+-------+-----------+----------+---------\n j      | jsonb |           | not null |\nIndexes:\n    \"j_idx\" gin (j jsonb_path_ops)\n\n-- 4.hcl --\nschema \"script_index_operator_class\" {}\n\ntable \"tsv\" {\n  schema = schema.$db\n  column \"t\" {\n    null = false\n    type = text\n  }\n  column \"a\" {\n    null = false\n    type = tsvector\n  }\n  index \"a_idx\" {\n    type = GiST\n    on {\n      column = column.a\n      ops    = sql(\"tsvector_ops(siglen=8)\")\n    }\n  }\n}\n\n-- 4.sql --\n      Table \"script_index_operator_class.tsv\"\n Column |   Type   | Collation | Nullable | Default\n--------+----------+-----------+----------+---------\n t      | text     |           | not null |\n a      | tsvector |           | not null |\nIndexes:\n    \"a_idx\" gist (a tsvector_ops (siglen='8'))\n\n\n-- 5.hcl --\nschema \"script_index_operator_class\" {}\n\ntable \"tsv\" {\n  schema = schema.$db\n  column \"t\" {\n    null = false\n    type = text\n  }\n  column \"a\" {\n    null = false\n    type = tsvector\n  }\n  index \"a_idx\" {\n    type = GiST\n    on {\n      column = column.a\n      ops    = sql(\"tsvector_ops(siglen=9)\")\n    }\n  }\n}\n\n-- 5.sql --\n      Table \"script_index_operator_class.tsv\"\n Column |   Type   | Collation | Nullable | Default\n--------+----------+-----------+----------+---------\n t      | text     |           | not null |\n a      | tsvector |           | not null |\nIndexes:\n    \"a_idx\" gist (a tsvector_ops (siglen='9'))"
  },
  {
    "path": "internal/integration/testdata/postgres/index-partial.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"active\" {\n    null = true\n    type = boolean\n  }\n  index \"users_name\" {\n    columns = [column.name]\n    where = \"active\"\n  }\n}\n\n-- 1.sql --\n        Table \"script_index_partial.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n name   | text    |           | not null |\n active | boolean |           |          |\nIndexes:\n    \"users_name\" btree (name) WHERE active\n\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"active\" {\n    null = true\n    type = boolean\n  }\n  index \"users_name\" {\n    columns = [column.name]\n    where = \"active AND name <> ''\"\n  }\n}\n\n-- 2.sql --\n        Table \"script_index_partial.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n name   | text    |           | not null |\n active | boolean |           |          |\nIndexes:\n    \"users_name\" btree (name) WHERE active AND name <> ''::text"
  },
  {
    "path": "internal/integration/testdata/postgres/index-type-brin.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\n# Add the \"page_per_range\" storage parameter.\napply 2.hcl\ncmpshow users 2.sql\n\n# Change the \"page_per_range\" storage parameter.\napply 3.hcl\ncmpshow users 3.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"c\" {\n    null = false\n    type = int\n  }\n  index \"users_c\" {\n    type = BRIN\n    columns = [column.c]\n  }\n}\n\n-- 1.sql --\n       Table \"script_index_type_brin.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n c      | integer |           | not null |\nIndexes:\n    \"users_c\" brin (c)\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"c\" {\n    null = false\n    type = int\n  }\n  index \"users_c\" {\n    type = BRIN\n    columns = [column.c]\n    page_per_range = 2\n  }\n}\n\n-- 2.sql --\n       Table \"script_index_type_brin.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n c      | integer |           | not null |\nIndexes:\n    \"users_c\" brin (c) WITH (pages_per_range='2')\n\n\n-- 3.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"c\" {\n    null = false\n    type = int\n  }\n  index \"users_c\" {\n    type = BRIN\n    columns = [column.c]\n    page_per_range = 3\n  }\n}\n\n-- 3.sql --\n       Table \"script_index_type_brin.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n c      | integer |           | not null |\nIndexes:\n    \"users_c\" brin (c) WITH (pages_per_range='3')"
  },
  {
    "path": "internal/integration/testdata/postgres/index-type.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\n# Change index type.\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"data\" {\n    null = true\n    type = jsonb\n  }\n  index \"users_name\" {\n    type = HASH\n    columns = [column.name]\n  }\n  index \"users_data\" {\n    type = GIN\n    columns = [column.data]\n  }\n}\n\n-- 1.sql --\n         Table \"script_index_type.users\"\n Column | Type  | Collation | Nullable | Default\n--------+-------+-----------+----------+---------\n name   | text  |           | not null |\n data   | jsonb |           |          |\nIndexes:\n    \"users_data\" gin (data)\n    \"users_name\" hash (name)\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"data\" {\n    null = true\n    type = jsonb\n  }\n  index \"users_name\" {\n    columns = [column.name]\n    # Index without \"using\" defaults to BTREE.\n  }\n  index \"users_data\" {\n    columns = [column.data]\n  }\n}\n\n-- 2.sql --\n         Table \"script_index_type.users\"\n Column | Type  | Collation | Nullable | Default\n--------+-------+-----------+----------+---------\n name   | text  |           | not null |\n data   | jsonb |           |          |\nIndexes:\n    \"users_data\" btree (data)\n    \"users_name\" btree (name)\n\n"
  },
  {
    "path": "internal/integration/testdata/postgres/index-unique-constraint.txtar",
    "content": "# Create table with UNIQUE constraint. i.e. implicit unique index.\nexecsql 'CREATE TABLE script_index_unique_constraint.users (name text, last text, nickname text UNIQUE, UNIQUE(name, last))'\ncmphcl 1.inspect.hcl\n\n# Dropping the unique index on the \"nickname\" column should drop the constraint as well.\napply 2.hcl\ncmpshow users 2.sql\n\napply 3.hcl\ncmpshow users 3.sql\n\natlas schema clean -u URL --auto-approve\natlas schema inspect -u file://4.sql --dev-url URL > got\ncmp got 4.inspect.hcl\n\n-- 1.inspect.hcl --\ntable \"users\" {\n  schema = schema.script_index_unique_constraint\n  column \"name\" {\n    null = true\n    type = text\n  }\n  column \"last\" {\n    null = true\n    type = text\n  }\n  column \"nickname\" {\n    null = true\n    type = text\n  }\n  unique \"users_name_last_key\" {\n    columns = [column.name, column.last]\n  }\n  unique \"users_nickname_key\" {\n    columns = [column.nickname]\n  }\n}\nschema \"script_index_unique_constraint\" {\n}\n\n-- 2.hcl --\ntable \"users\" {\n  schema = schema.script_index_unique_constraint\n  column \"name\" {\n    null = true\n    type = text\n  }\n  column \"last\" {\n    null = true\n    type = text\n  }\n  column \"nickname\" {\n    null = true\n    type = text\n  }\n  unique \"users_name_last_key\" {\n    columns = [column.name, column.last]\n  }\n}\nschema \"script_index_unique_constraint\" {\n}\n\n-- 2.sql --\n   Table \"script_index_unique_constraint.users\"\n  Column  | Type | Collation | Nullable | Default\n----------+------+-----------+----------+---------\n name     | text |           |          |\n last     | text |           |          |\n nickname | text |           |          |\nIndexes:\n    \"users_name_last_key\" UNIQUE CONSTRAINT, btree (name, last)\n\n-- 3.hcl --\ntable \"users\" {\n  schema = schema.script_index_unique_constraint\n  column \"name\" {\n    null = true\n    type = text\n  }\n  column \"last\" {\n    null = true\n    type = text\n  }\n  column \"nickname\" {\n    null = true\n    type = text\n  }\n}\nschema \"script_index_unique_constraint\" {\n}\n\n-- 3.sql --\n   Table \"script_index_unique_constraint.users\"\n  Column  | Type | Collation | Nullable | Default\n----------+------+-----------+----------+---------\n name     | text |           |          |\n last     | text |           |          |\n nickname | text |           |          |\n-- 4.sql --\ncreate table t1(a int primary key, b int unique);\ncreate table t0(b int primary key references t1(b));\ncreate table t2(c int primary key references t1(b));\ncreate table d(c int unique references t1(b));\n\n-- 4.inspect.hcl --\ntable \"d\" {\n  schema = schema.script_index_unique_constraint\n  column \"c\" {\n    null = true\n    type = integer\n  }\n  foreign_key \"d_c_fkey\" {\n    columns     = [column.c]\n    ref_columns = [table.t1.column.b]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n  unique \"d_c_key\" {\n    columns = [column.c]\n  }\n}\ntable \"t0\" {\n  schema = schema.script_index_unique_constraint\n  column \"b\" {\n    null = false\n    type = integer\n  }\n  primary_key {\n    columns = [column.b]\n  }\n  foreign_key \"t0_b_fkey\" {\n    columns     = [column.b]\n    ref_columns = [table.t1.column.b]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n}\ntable \"t1\" {\n  schema = schema.script_index_unique_constraint\n  column \"a\" {\n    null = false\n    type = integer\n  }\n  column \"b\" {\n    null = true\n    type = integer\n  }\n  primary_key {\n    columns = [column.a]\n  }\n  unique \"t1_b_key\" {\n    columns = [column.b]\n  }\n}\ntable \"t2\" {\n  schema = schema.script_index_unique_constraint\n  column \"c\" {\n    null = false\n    type = integer\n  }\n  primary_key {\n    columns = [column.c]\n  }\n  foreign_key \"t2_c_fkey\" {\n    columns     = [column.c]\n    ref_columns = [table.t1.column.b]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n}\nschema \"script_index_unique_constraint\" {\n}"
  },
  {
    "path": "internal/integration/testdata/postgres/primary-key.txtar",
    "content": "only postgres15\n\n# Create table.\napply 1.hcl\ncmpshow users 1.sql\n\n# Add a primary-key.\napply 2.hcl\ncmpshow users 2.sql\n\n# Modify the primary-key include columns.\napply 3.hcl\ncmpshow users 3.sql\n\n# Drop the primary-key.\napply 1.hcl\ncmpshow users 1.sql\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"c\" {\n    null = true\n    type = int\n  }\n}\n\n-- 1.sql --\n         Table \"script_primary_key.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n id     | integer |           | not null |\n c      | integer |           |          |\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"c\" {\n    null = true\n    type = int\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\n\n-- 2.sql --\n         Table \"script_primary_key.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n id     | integer |           | not null |\n c      | integer |           |          |\nIndexes:\n    \"users_pkey\" PRIMARY KEY, btree (id)\n\n\n-- 3.hcl --\nschema \"$db\" {}\n\ntable \"users\" {\n  schema = schema.$db\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"c\" {\n    null = true\n    type = int\n  }\n  primary_key {\n    columns = [column.id]\n    include = [column.c]\n  }\n}\n\n-- 3.sql --\n         Table \"script_primary_key.users\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n id     | integer |           | not null |\n c      | integer |           |          |\nIndexes:\n    \"users_pkey\" PRIMARY KEY, btree (id) INCLUDE (c)\n\n\n"
  },
  {
    "path": "internal/integration/testdata/postgres/table-checks.txtar",
    "content": "# Inspect SQL format.\natlas schema inspect --url file://schema.sql --dev-url URL --format '{{ sql . \"  \" }}' > got\ncmp schema.inspected.sql got\n# Inspect HCL format.\natlas schema inspect --url file://schema.sql --dev-url URL > got\ncmp schema.inspected.hcl got\n\natlas migrate diff v1 --to file://schema.sql --dev-url URL --format '{{ sql . \"  \" }}'\ncmpmig 0 migration.v1.sql\natlas migrate diff v1-check --to file://schema.sql --dev-url URL --format '{{ sql . \"  \" }}'\nstdout 'The migration directory is synced with the desired state, no changes to be made'\n\natlas migrate diff v2 --to file://schema.v2.sql --dev-url URL --format '{{ sql . \"  \" }}'\ncmpmig 1 migration.v2.sql\natlas migrate diff v2-check --to file://schema.v2.sql --dev-url URL --format '{{ sql . \"  \" }}'\nstdout 'The migration directory is synced with the desired state, no changes to be made'\n\natlas migrate diff v3 --to file://schema.v3.sql --dev-url URL --format '{{ sql . \"  \" }}'\ncmpmig 2 migration.v3.sql\natlas migrate diff v3-check --to file://schema.v3.sql --dev-url URL --format '{{ sql . \"  \" }}'\nstdout 'The migration directory is synced with the desired state, no changes to be made'\n\n-- schema.sql --\ncreate table t1 (\n  a int constraint c1 check (a > 0),\n  b int constraint c2 check (b > 0),\n  constraint c3 check (a < b)\n);\ncreate table t2 (\n  a int constraint c1 check (a > 0),\n  c int constraint c4 check (c > 0),\n  constraint c5 check (a < c)\n);\n-- schema.inspected.sql --\n-- Create \"t1\" table\nCREATE TABLE \"t1\" (\n  \"a\" integer NULL,\n  \"b\" integer NULL,\n  CONSTRAINT \"c1\" CHECK (a > 0),\n  CONSTRAINT \"c2\" CHECK (b > 0),\n  CONSTRAINT \"c3\" CHECK (a < b)\n);\n-- Create \"t2\" table\nCREATE TABLE \"t2\" (\n  \"a\" integer NULL,\n  \"c\" integer NULL,\n  CONSTRAINT \"c1\" CHECK (a > 0),\n  CONSTRAINT \"c4\" CHECK (c > 0),\n  CONSTRAINT \"c5\" CHECK (a < c)\n);\n-- schema.inspected.hcl --\ntable \"t1\" {\n  schema = schema.script_table_checks\n  column \"a\" {\n    null = true\n    type = integer\n  }\n  column \"b\" {\n    null = true\n    type = integer\n  }\n  check \"c1\" {\n    expr = \"(a > 0)\"\n  }\n  check \"c2\" {\n    expr = \"(b > 0)\"\n  }\n  check \"c3\" {\n    expr = \"(a < b)\"\n  }\n}\ntable \"t2\" {\n  schema = schema.script_table_checks\n  column \"a\" {\n    null = true\n    type = integer\n  }\n  column \"c\" {\n    null = true\n    type = integer\n  }\n  check \"c1\" {\n    expr = \"(a > 0)\"\n  }\n  check \"c4\" {\n    expr = \"(c > 0)\"\n  }\n  check \"c5\" {\n    expr = \"(a < c)\"\n  }\n}\nschema \"script_table_checks\" {\n}\n-- migration.v1.sql --\n-- Create \"t1\" table\nCREATE TABLE \"t1\" (\n  \"a\" integer NULL,\n  \"b\" integer NULL,\n  CONSTRAINT \"c1\" CHECK (a > 0),\n  CONSTRAINT \"c2\" CHECK (b > 0),\n  CONSTRAINT \"c3\" CHECK (a < b)\n);\n-- Create \"t2\" table\nCREATE TABLE \"t2\" (\n  \"a\" integer NULL,\n  \"c\" integer NULL,\n  CONSTRAINT \"c1\" CHECK (a > 0),\n  CONSTRAINT \"c4\" CHECK (c > 0),\n  CONSTRAINT \"c5\" CHECK (a < c)\n);\n-- schema.v2.sql --\ncreate table t1 (\n  a int constraint c1 check (a > 1),\n  b int constraint c2 check (b > 1),\n  constraint c3 check (a < b)\n);\ncreate table t2 (\n  a int constraint c1 check (a > 1),\n  c int constraint c4 check (c > 1),\n  constraint c5 check (a < c)\n);\n-- migration.v2.sql --\n-- Modify \"t1\" table\nALTER TABLE \"t1\" DROP CONSTRAINT \"c1\", ADD CONSTRAINT \"c1\" CHECK (a > 1), DROP CONSTRAINT \"c2\", ADD CONSTRAINT \"c2\" CHECK (b > 1);\n-- Modify \"t2\" table\nALTER TABLE \"t2\" DROP CONSTRAINT \"c1\", ADD CONSTRAINT \"c1\" CHECK (a > 1), DROP CONSTRAINT \"c4\", ADD CONSTRAINT \"c4\" CHECK (c > 1);\n-- schema.v3.sql --\ncreate table t1 (\n  a int constraint c1 check (a > 1),\n  b int constraint c2 check (b > 1),\n  -- Rename constraint.\n  constraint c4 check (a < b)\n);\ncreate table t2 (\n  a int constraint c1 check (a > 1),\n  c int constraint c4 check (c > 1),\n  -- Rename constraint.\n  constraint c6 check (a < c)\n);\n-- migration.v3.sql --\n-- Modify \"t1\" table\nALTER TABLE \"t1\" DROP CONSTRAINT \"c3\", ADD CONSTRAINT \"c4\" CHECK (a < b);\n-- Modify \"t2\" table\nALTER TABLE \"t2\" DROP CONSTRAINT \"c5\", ADD CONSTRAINT \"c6\" CHECK (a < c);"
  },
  {
    "path": "internal/integration/testdata/postgres/table-partition.txtar",
    "content": "apply 1.hcl\ncmpshow logs 1.sql\n\n# Changing partitioned table is not allowed.\n! 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)'\n\n# Drop all tables.\napply drop.hcl\n\n# Recreate partitioned table.\napply 2.hcl\ncmpshow logs 2.sql\n\n# Drop all tables.\napply drop.hcl\n\napply 3.hcl\ncmpshow measurement 3.sql\ncmphcl 3.inspect.hcl\nexecsql 'CREATE TABLE measurement_y2006m02 PARTITION OF $db.measurement FOR VALUES FROM (''2006-02-01'') TO (''2006-03-01'')'\ncmpshow measurement 3.partition.sql\n\n# Drop all tables.\napply drop.hcl\n\napply 4.hcl\ncmpshow metrics 4.sql\ncmphcl 4.inspect.hcl\n\n-- 1.hcl --\nschema \"$db\" {}\n\ntable \"logs\" {\n  schema = schema.$db\n  column \"value\" {\n    null = false\n    type = integer\n  }\n  partition {\n    type = LIST\n    columns = [column.value]\n  }\n}\n\n-- postgres10/1.sql --\n        Table \"script_table_partition.logs\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n value  | integer |           | not null |\nPartition key: LIST (value)\n\n-- postgres11/1.sql --\n        Table \"script_table_partition.logs\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n value  | integer |           | not null |\nPartition key: LIST (value)\nNumber of partitions: 0\n\n-- 1.sql --\n  Partitioned table \"script_table_partition.logs\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n value  | integer |           | not null |\nPartition key: LIST (value)\nNumber of partitions: 0\n\n-- 2.hcl --\nschema \"$db\" {}\n\ntable \"logs\" {\n  schema = schema.$db\n  column \"a\" {\n    null = false\n    type = integer\n  }\n  column \"b\" {\n    null = false\n    type = integer\n  }\n  partition {\n    type = RANGE\n    by {\n      column = column.a\n    }\n    by {\n      expr = \"b * (a % 2)\"\n    }\n  }\n}\n\n-- postgres10/2.sql --\n        Table \"script_table_partition.logs\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n a      | integer |           | not null |\n b      | integer |           | not null |\nPartition key: RANGE (a, ((b * (a % 2))))\n\n-- postgres11/2.sql --\n        Table \"script_table_partition.logs\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n a      | integer |           | not null |\n b      | integer |           | not null |\nPartition key: RANGE (a, ((b * (a % 2))))\nNumber of partitions: 0\n\n-- 2.sql --\n  Partitioned table \"script_table_partition.logs\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n a      | integer |           | not null |\n b      | integer |           | not null |\nPartition key: RANGE (a, ((b * (a % 2))))\nNumber of partitions: 0\n\n-- 3.hcl --\nschema \"$db\" {}\n\n# The partitioned table from the PostgreSQL doc.\ntable \"measurement\" {\n  schema = schema.$db\n  column \"city_id\" {\n    null = false\n    type = integer\n  }\n  column \"logdate\" {\n    null = false\n    type = date\n  }\n  column \"peaktemp\" {\n    null = true\n    type = int\n  }\n  column \"unitsales\" {\n    null = true\n    type = int\n  }\n  partition {\n    type = RANGE\n    columns = [column.logdate]\n  }\n}\n\n-- postgres10/3.sql --\n      Table \"script_table_partition.measurement\"\n  Column   |  Type   | Collation | Nullable | Default\n-----------+---------+-----------+----------+---------\n city_id   | integer |           | not null |\n logdate   | date    |           | not null |\n peaktemp  | integer |           |          |\n unitsales | integer |           |          |\nPartition key: RANGE (logdate)\n\n-- postgres11/3.sql --\n      Table \"script_table_partition.measurement\"\n  Column   |  Type   | Collation | Nullable | Default\n-----------+---------+-----------+----------+---------\n city_id   | integer |           | not null |\n logdate   | date    |           | not null |\n peaktemp  | integer |           |          |\n unitsales | integer |           |          |\nPartition key: RANGE (logdate)\nNumber of partitions: 0\n\n-- 3.sql --\nPartitioned table \"script_table_partition.measurement\"\n  Column   |  Type   | Collation | Nullable | Default\n-----------+---------+-----------+----------+---------\n city_id   | integer |           | not null |\n logdate   | date    |           | not null |\n peaktemp  | integer |           |          |\n unitsales | integer |           |          |\nPartition key: RANGE (logdate)\nNumber of partitions: 0\n\n\n-- postgres10/3.partition.sql --\n      Table \"script_table_partition.measurement\"\n  Column   |  Type   | Collation | Nullable | Default\n-----------+---------+-----------+----------+---------\n city_id   | integer |           | not null |\n logdate   | date    |           | not null |\n peaktemp  | integer |           |          |\n unitsales | integer |           |          |\nPartition key: RANGE (logdate)\nNumber of partitions: 1 (Use \\d+ to list them.)\n\n-- postgres11/3.partition.sql --\n      Table \"script_table_partition.measurement\"\n  Column   |  Type   | Collation | Nullable | Default\n-----------+---------+-----------+----------+---------\n city_id   | integer |           | not null |\n logdate   | date    |           | not null |\n peaktemp  | integer |           |          |\n unitsales | integer |           |          |\nPartition key: RANGE (logdate)\nNumber of partitions: 1 (Use \\d+ to list them.)\n\n-- 3.partition.sql --\nPartitioned table \"script_table_partition.measurement\"\n  Column   |  Type   | Collation | Nullable | Default\n-----------+---------+-----------+----------+---------\n city_id   | integer |           | not null |\n logdate   | date    |           | not null |\n peaktemp  | integer |           |          |\n unitsales | integer |           |          |\nPartition key: RANGE (logdate)\nNumber of partitions: 1 (Use \\d+ to list them.)\n\n-- 3.inspect.hcl --\ntable \"measurement\" {\n  schema = schema.script_table_partition\n  column \"city_id\" {\n    null = false\n    type = integer\n  }\n  column \"logdate\" {\n    null = false\n    type = date\n  }\n  column \"peaktemp\" {\n    null = true\n    type = integer\n  }\n  column \"unitsales\" {\n    null = true\n    type = integer\n  }\n  partition {\n    type    = RANGE\n    columns = [column.logdate]\n  }\n}\nschema \"script_table_partition\" {\n}\n\n-- 4.hcl --\nschema \"$db\" {}\n\ntable \"metrics\" {\n  schema = schema.$db\n  column \"x\" {\n    null = false\n    type = integer\n  }\n  column \"y\" {\n    null = false\n    type = integer\n  }\n  partition {\n    type = RANGE\n    by {\n        column = column.x\n    }\n    by {\n        expr = \"floor(x)\"\n    }\n    by {\n        expr = \"y * 2\"\n    }\n    by {\n        expr = \"floor(y)\"\n    }\n  }\n}\n\n-- postgres10/4.sql --\n      Table \"script_table_partition.metrics\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n x      | integer |           | not null |\n y      | integer |           | not null |\nPartition key: RANGE (x, floor((x)::double precision), ((y * 2)), floor((y)::double precision))\n\n-- postgres11/4.sql --\n      Table \"script_table_partition.metrics\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n x      | integer |           | not null |\n y      | integer |           | not null |\nPartition key: RANGE (x, floor((x)::double precision), ((y * 2)), floor((y)::double precision))\nNumber of partitions: 0\n\n-- 4.sql --\nPartitioned table \"script_table_partition.metrics\"\n Column |  Type   | Collation | Nullable | Default\n--------+---------+-----------+----------+---------\n x      | integer |           | not null |\n y      | integer |           | not null |\nPartition key: RANGE (x, floor((x)::double precision), ((y * 2)), floor((y)::double precision))\nNumber of partitions: 0\n\n-- 4.inspect.hcl --\ntable \"metrics\" {\n  schema = schema.script_table_partition\n  column \"x\" {\n    null = false\n    type = integer\n  }\n  column \"y\" {\n    null = false\n    type = integer\n  }\n  partition {\n    type = RANGE\n    by {\n      column = column.x\n    }\n    by {\n      expr = \"floor((x)::double precision)\"\n    }\n    by {\n      expr = \"(y * 2)\"\n    }\n    by {\n      expr = \"floor((y)::double precision)\"\n    }\n  }\n}\nschema \"script_table_partition\" {\n}\n\n-- drop.hcl --\nschema \"$db\" {}"
  },
  {
    "path": "internal/integration/testdata/sqlite/autoincrement.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\n-- 1.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = integer\n    auto_increment = true\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT)"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-apply-multifile.txtar",
    "content": "atlas schema apply -f users.hcl -f schema.hcl -u URL --auto-approve\ncmpshow users expected.sql\n\n-- users.hcl --\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"status\" {\n    null = true\n    type = text\n    default = \"hello\"\n  }\n}\n-- schema.hcl --\nschema \"main\" {\n}\n-- expected.sql --\nCREATE TABLE `users` (\n  `id` int NOT NULL,\n  `status` text NULL DEFAULT 'hello'\n)"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-apply-project-multifile.txtar",
    "content": "atlas schema apply --env local --auto-approve\ncmpshow users expected.sql\n\n-- atlas.hcl --\nenv \"local\" {\n    url = \"URL\"\n    src = \"./schema\"\n    def_val = \"hello\"\n}\n-- schema/vars.hcl --\nvariable \"def_val\" {\n    type = string\n}\n-- schema/table.hcl --\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"status\" {\n    null = true\n    type = text\n    default = var.def_val\n  }\n}\n-- schema/schema.hcl --\nschema \"main\" {\n}\n-- expected.sql --\nCREATE TABLE `users` (\n  `id` int NOT NULL,\n  `status` text NULL DEFAULT 'hello'\n)"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-apply-vars.txtar",
    "content": "! atlas schema apply --env local --auto-approve\nstderr 'missing value for required variable \"def_val\"'\n\natlas schema apply --env local_with_vals --auto-approve\ncmpshow users expected.sql\n\n-- atlas.hcl --\nenv \"local\" {\n    url = \"URL\"\n    src = \"./1.hcl\"\n}\nenv \"local_with_vals\" {\n    url = \"URL\"\n    src = \"./1.hcl\"\n\n    def_val = \"hello\"\n}\n-- 1.hcl --\nvariable \"def_val\" {\n    type = string\n}\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"status\" {\n    null = true\n    type = text\n    default = var.def_val\n  }\n}\nschema \"main\" {\n}\n-- expected.sql --\nCREATE TABLE `users` (\n  `id` int NOT NULL,\n  `status` text NULL DEFAULT 'hello'\n)"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-inspect.txtar",
    "content": "apply 1.hcl\n\n# test url flag\natlas schema inspect -u URL > inspected.hcl\ncmp inspected.hcl 1.hcl\n\n# test exclude flag on table.\natlas schema inspect -u URL --exclude \"users\" > inspected.hcl\ncmp inspected.hcl notable.hcl\n\n# test exclude flag on column.\natlas schema inspect -u URL --exclude \"*.[ab]*\" > inspected.hcl\ncmp inspected.hcl id.hcl\n\n# test exclude flag on column.\natlas schema inspect -u URL --exclude \"*.*\" > inspected.hcl\ncmp inspected.hcl nocolumn.hcl\n\n\n-- 1.hcl --\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"a\" {\n    null = false\n    type = int\n  }\n  column \"b\" {\n    null = false\n    type = int\n  }\n  column \"ab\" {\n    null = false\n    type = int\n  }\n  column \"ac\" {\n    null = false\n    type = uint64\n  }\n}\nschema \"main\" {\n}\n-- empty.hcl --\n-- notable.hcl --\nschema \"main\" {\n}\n-- id.hcl --\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nschema \"main\" {\n}\n-- nocolumn.hcl --\ntable \"users\" {\n  schema = schema.main\n}\nschema \"main\" {\n}"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-apply.txtar",
    "content": "! atlas migrate apply\nstderr 'Error: checksum file not found'\nstdout 'You have a checksum error in your migration directory.'\nstdout 'atlas migrate hash'\n\natlas migrate hash\n\n# Apply all of them\natlas migrate apply --url URL\nstdout 'Migrating to version 2 \\(2 migrations in total\\):'\nstdout '-- migrating version 1'\nstdout '-> CREATE TABLE `users` \\('\nstdout '  `id` integer NOT NULL,'\nstdout '  `age` integer NOT NULL,'\nstdout '  `name` TEXT NOT NULL,'\nstdout '  PRIMARY KEY \\(`id`\\)'\nstdout '\\);'\nstdout '-- migrating version 2'\nstdout '-> CREATE TABLE `pets` \\(`id` integer NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY \\(`id`\\)\\);'\nstdout '-- 2 migrations'\nstdout '-- 2 sql statements'\ncmpshow users users.sql\ncmpshow pets pets.sql\n\natlas migrate apply --url URL 1\nstdout 'No migration files to execute'\n\nclearSchema\n\n# Apply one by one\natlas migrate apply --url URL 1\nstdout 'Migrating to version 1 \\(1 migrations in total\\):'\ncmpshow users users.sql\n\natlas migrate apply --url URL 1\nstdout 'Migrating to version 2 from 1 \\(1 migrations in total\\):'\ncmpshow users users.sql\ncmpshow pets pets.sql\n\natlas migrate apply --url URL 1\nstdout 'No migration files to execute'\n\nclearSchema\n\n# Move the broken migration into the migrations directory and check the different transaction modes.\ncp broken.sql migrations/3_third.sql\natlas migrate hash\n\n! atlas migrate apply --url URL --tx-mode invalid\nstderr 'unknown tx-mode \"invalid\"'\n\n# Test --tx-mode all\n\n! atlas migrate apply --url URL --tx-mode all\nstderr 'executing statement \"THIS IS A FAILING STATEMENT;\" from version \"3\"'\natlas schema inspect --url URL --exclude atlas_schema_revisions\ncmp stdout empty.hcl\n\n# Apply one migration, after rolling everything back, the first revision must still exist.\natlas migrate apply --url URL 1\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users\ncmp stdout empty.hcl\ncmpshow users users.sql\n\n! atlas migrate apply --url URL --tx-mode all\nstderr 'executing statement \"THIS IS A FAILING STATEMENT;\" from version \"3\"'\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users\ncmp stdout empty.hcl\n\n# If the broken migration is gone, we can apply everything without any problems.\nrm migrations/3_third.sql\natlas migrate hash\n\natlas migrate apply --url URL --revisions-schema $db\ncmpshow users users.sql\ncmpshow pets pets.sql\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets\ncmp stdout empty.hcl\n\nclearSchema\n\n# Test --tx-mode file\n\ncp broken.sql migrations/3_third.sql\natlas migrate hash\n\n! atlas migrate apply --url URL --tx-mode file\nstderr 'executing statement \"THIS IS A FAILING STATEMENT;\" from version \"3\"'\natlas schema inspect --url URL --exclude atlas_schema_revisions\ncmpshow users users.sql\ncmpshow pets pets.sql\n\n# Table \"broken\" does not exist since we rolled back that migration.\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets\ncmp stdout empty.hcl\n\n# If the broken migration is gone, we can apply everything without any problems.\nrm migrations/3_third.sql\natlas migrate hash\n\natlas migrate apply --url URL --revisions-schema $db\ncmpshow users users.sql\ncmpshow pets pets.sql\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets\ncmp stdout empty.hcl\n\nclearSchema\n\n# Test --tx-mode none\n\ncp broken.sql migrations/3_third.sql\natlas migrate hash\n\n! atlas migrate apply --url URL --tx-mode none\nstderr 'executing statement \"THIS IS A FAILING STATEMENT;\" from version \"3\"'\natlas schema inspect --url URL --exclude atlas_schema_revisions\ncmpshow users users.sql\ncmpshow pets pets.sql\n\n# Table \"broken\" does exist since we do not have transactions.\natlas schema inspect --url URL --exclude atlas_schema_revisions --exclude users --exclude pets\ncmp stdout broken.hcl\n\n-- migrations/1_first.sql --\nCREATE TABLE `users` (\n  `id` integer NOT NULL,\n  `age` integer NOT NULL,\n  `name` TEXT NOT NULL,\n  PRIMARY KEY (`id`)\n);\n\n-- migrations/2_second.sql --\nCREATE TABLE `pets` (`id` integer NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY (`id`));\n\n-- broken.sql --\nCREATE TABLE `broken` (`id` integer);\nTHIS IS A FAILING STATEMENT;\n\n-- empty.hcl --\nschema \"main\" {\n}\n-- broken.hcl --\ntable \"broken\" {\n  schema = schema.main\n  column \"id\" {\n    null = true\n    type = integer\n  }\n}\nschema \"main\" {\n}\n-- users.sql --\nCREATE TABLE `users` (\n  `id` integer NOT NULL,\n  `age` integer NOT NULL,\n  `name` TEXT NOT NULL,\n  PRIMARY KEY (`id`)\n)\n\n-- pets.sql --\nCREATE TABLE `pets` (`id` integer NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY (`id`))\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-diff-datasrc-hcl-paths.txtar",
    "content": "atlas migrate diff --env local\ncmpmig 0 expected.sql\n\n-- atlas.hcl --\ndata \"hcl_schema\" \"app\" {\n  paths = glob(\"schema-*.hcl\")\n  vars = {\n    default_value = \"unknown\"\n  }\n}\n\nenv \"local\" {\n  src = data.hcl_schema.app.url\n  dev = \"sqlite://dev?mode=memory&_fk=1\"\n}\n\n-- schema-1.hcl --\nschema \"main\" {}\n\ntable \"pets\" {\n  schema = schema.main\n  column \"name\" {\n    null    = false\n    type    = text\n    default = var.default_value\n  }\n  column \"owner_id\" {\n    type = integer\n  }\n  foreign_key \"owner_id\" {\n    columns     = [column.owner_id]\n    ref_columns = [table.users.column.id]\n    on_update   = NO_ACTION\n    on_delete   = NO_ACTION\n  }\n}\n\n-- schema-2.hcl --\nvariable \"default_value\" {\n  type = string\n}\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = true\n    type = integer\n  }\n  column \"name\" {\n    null    = false\n    type    = text\n    default = var.default_value\n  }\n}\n\n-- expected.sql --\n-- Create \"pets\" table\nCREATE 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);\n-- Create \"users\" table\nCREATE TABLE `users` (`id` integer NULL, `name` text NOT NULL DEFAULT 'unknown');\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-diff-datasrc-hcl.txtar",
    "content": "atlas migrate diff --env local\ncmpmig 0 expected.sql\n\n-- atlas.hcl --\ndata \"hcl_schema\" \"app\" {\n  path = \"schema.hcl\"\n  vars = {\n    default_value = \"unknown\"\n  }\n}\n\nenv \"local\" {\n    src = data.hcl_schema.app.url\n    dev = \"sqlite://dev?mode=memory&_fk=1\"\n}\n\n-- schema.hcl --\nvariable \"default_value\" {\n  type = string\n}\n\nschema \"main\" {}\n\ntable \"users\" {\n  schema = schema.main\n  column \"name\" {\n    null    = false\n    type    = text\n    default = var.default_value\n  }\n}\n\n-- expected.sql --\n-- Create \"users\" table\nCREATE TABLE `users` (`name` text NOT NULL DEFAULT 'unknown');\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-diff-minimal-env.txtar",
    "content": "atlas migrate diff --env local\ncmpmig 0 diff.sql\n-- atlas.hcl --\nenv \"local\" {\n    src = \"1.hcl\"\n    dev = \"sqlite://devdb\"\n}\n-- 1.hcl --\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nschema \"main\" {\n}\n-- diff.sql --\n-- Create \"users\" table\nCREATE TABLE `users` (`id` int NOT NULL);"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-diff-multifile.txtar",
    "content": "! atlas migrate diff --dev-url sqlite://devdb --to file://schema/ --to other://scheme --dir file://migrations\nstderr 'got mixed --to url schemes'\n\n! atlas migrate diff --dev-url sqlite://devdb --to mysql://localhost/x --to mysql://localhost/y --dir file://migrations\nstderr 'got multiple --to urls of scheme'\n\natlas migrate diff --dev-url sqlite://devdb --to file://schema/ --dir file://migrations\ncmpmig 0 diff.sql\n\n# reset dir\nexec rm -rf migrations/\n\natlas migrate diff --dev-url sqlite://devdb --to file://schema/schema.hcl --to file://schema/table.hcl --dir file://migrations\ncmpmig 0 diff.sql\n\n-- schema/schema.hcl --\nschema \"main\" {\n}\n-- schema/table.hcl --\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\n-- diff.sql --\n-- Create \"users\" table\nCREATE TABLE `users` (`id` int NOT NULL);"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-diff-sql.txtar",
    "content": "atlas migrate diff --dev-url sqlite://dev --to file://schema.sql --dir file://migrations\ncmpmig 0 diff.sql\n\natlas migrate diff --dev-url sqlite://dev --to file://schema.sql --dir file://migrations\nstdout 'The migration directory is synced with the desired state, no changes to be made'\n\natlas schema diff --dev-url sqlite://dev?mode=memory --from file://migrations --to file://schema.sql --exclude atlas_schema_revisions\nstdout 'Schemas are synced, no changes to be made.'\n\n-- schema.sql --\n-- Create \"records\" table\nCREATE TABLE IF NOT EXISTS `records` (\n    `id` integer NOT NULL PRIMARY KEY AUTOINCREMENT,\n    `name` varchar(255) NOT NULL DEFAULT ''  UNIQUE,\n    `price` decimal NOT NULL DEFAULT 0\n);\nCREATE INDEX `records_price` ON `records` (`price`);\n\n-- Create \"categories\" table\nCREATE TABLE IF NOT EXISTS categories (\n  id INTEGER NOT NULL PRIMARY KEY,\n  category_name VARCHAR(255) NOT NULL\n);\n\n-- Create \"products\" table\nCREATE TABLE IF NOT EXISTS products (\n  id INTEGER NOT NULL PRIMARY KEY,\n  product_name VARCHAR(255) NOT NULL UNIQUE,\n  price DECIMAL(10,2) NOT NULL,\n  category_id INTEGER,\n  FOREIGN KEY (category_id) REFERENCES categories (id) ON DELETE SET NULL\n);\n\n-- diff.sql --\n-- Create \"records\" table\nCREATE TABLE `records` (`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT, `name` varchar NOT NULL DEFAULT '', `price` decimal NOT NULL DEFAULT 0);\n-- Create index \"records_name\" to table: \"records\"\nCREATE UNIQUE INDEX `records_name` ON `records` (`name`);\n-- Create index \"records_price\" to table: \"records\"\nCREATE INDEX `records_price` ON `records` (`price`);\n-- Create \"categories\" table\nCREATE TABLE `categories` (`id` integer NOT NULL, `category_name` varchar NOT NULL, PRIMARY KEY (`id`));\n-- Create \"products\" table\nCREATE 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);\n-- Create index \"products_product_name\" to table: \"products\"\nCREATE UNIQUE INDEX `products_product_name` ON `products` (`product_name`);"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-diff.txtar",
    "content": "exec mkdir migrations\n\n! atlas migrate diff --to file://1.hcl --dir file://migrations\nstderr '\"dev-url\" not set'\n\n! atlas migrate diff --dev-url sqlite://devdb --dir file://migrations\nstderr '\"to\" not set'\n\natlas migrate diff --dev-url sqlite://devdb --to file://1.hcl --dir file://migrations\ncmpmig 0 diff.sql\n-- 1.hcl --\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nschema \"main\" {\n}\n-- diff.sql --\n-- Create \"users\" table\nCREATE TABLE `users` (`id` int NOT NULL);"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-lint-add-notnull.txtar",
    "content": "atlas migrate lint --dir file://migrations --dev-url URL --latest=2\nstdout 'Analyzing changes until version 2 \\(2 migrations in total\\):'\nstdout ''\nstdout '  -- analyzing version 1'\nstdout '    -- no diagnostics found'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -- analyzing version 2'\nstdout '    -- data dependent changes detected:'\nstdout '      -- L1: Adding a non-nullable \"int\" column \"c2\" will fail in case table \"users\" is not empty'\nstdout '         https://atlasgo.io/lint/analyzers#MF103'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -------------------------'\nstdout '  -- .+'\nstdout '  -- 1 version ok, 1 with warnings'\nstdout '  -- 4 schema changes'\nstdout '  -- 1 diagnostic'\n\n-- migrations/1.sql --\nCREATE TABLE users (id int);\n\n/* Adding a not-null column without default to a table created in this file should not report. */\nALTER TABLE users ADD COLUMN c1 int NOT NULL;\n\n-- migrations/2.sql --\nALTER TABLE users ADD COLUMN c2 int NOT NULL;\n\nALTER TABLE users ADD COLUMN c3 int NOT NULL DEFAULT 1;\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-lint-destructive.txtar",
    "content": "# Expect the command to fail; exit code 1.\n! atlas migrate lint --dir file://migrations --dev-url URL --latest=1\nstdout 'Analyzing changes from version 2 to 3 \\(1 migration in total\\):'\nstdout ''\nstdout '  -- analyzing version 3'\nstdout '    -- destructive changes detected:'\nstdout '      -- L1: Dropping table \"pets\" https://atlasgo.io/lint/analyzers#DS102'\nstdout '    -- suggested fix:'\nstdout '      -> Add a pre-migration check to ensure table \"pets\" is empty before dropping it'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -------------------------'\nstdout '  -- .+'\nstdout '  -- 1 version with errors'\nstdout '  -- 1 schema change'\nstdout '  -- 1 diagnostic'\n\n# Expect the command to fail; exit code 1.\n! atlas migrate lint --dir file://migrations --dev-url URL --latest=2\nstdout 'Analyzing changes from version 1 to 3 \\(2 migrations in total\\):'\nstdout ''\nstdout '  -- analyzing version 2'\nstdout '    -- destructive changes detected:'\nstdout '      -- L1: Dropping table \"users\" https://atlasgo.io/lint/analyzers#DS102'\nstdout '    -- suggested fix:'\nstdout '      -> Add a pre-migration check to ensure table \"users\" is empty before dropping it'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -- analyzing version 3'\nstdout '    -- destructive changes detected:'\nstdout '      -- L1: Dropping table \"pets\" https://atlasgo.io/lint/analyzers#DS102'\nstdout '    -- suggested fix:'\nstdout '      -> Add a pre-migration check to ensure table \"pets\" is empty before dropping it'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -------------------------'\nstdout '  -- .+'\nstdout '  -- 2 versions with errors'\nstdout '  -- 2 schema changes'\nstdout '  -- 2 diagnostics'\n\n-- migrations/1.sql --\nCREATE TABLE users (id int);\n\nCREATE TABLE pets (id int);\n\nALTER TABLE users RENAME COLUMN id TO oid;\n\n-- migrations/2.sql --\nDROP TABLE users;\n\n-- migrations/3.sql --\nDROP TABLE pets;\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-lint-ignore.txtar",
    "content": "# Ignore all diagnostics.\natlas migrate lint --dir file://migrations1 --dev-url URL --latest=1\nstdout 'Analyzing changes from version 1 to 2 \\(1 migration in total\\):'\nstdout ''\nstdout '  -- analyzing version 2'\nstdout '    -- no diagnostics found'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -------------------------'\nstdout '  -- .+'\nstdout '  -- 1 version ok'\nstdout '  -- 2 schema changes'\n\n# Ignore specific diagnostics.\natlas migrate lint --dir file://migrations2 --dev-url URL --latest=1\nstdout 'Analyzing changes from version 1 to 2 \\(1 migration in total\\):'\nstdout ''\nstdout '  -- analyzing version 2'\nstdout '    -- no diagnostics found'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -------------------------'\nstdout '  -- .+'\nstdout '  -- 1 version ok'\nstdout '  -- 2 schema changes'\n\n# Ignore by code.\natlas migrate lint --dir file://migrations3 --dev-url URL --latest=1\nstdout 'Analyzing changes from version 1 to 2 \\(1 migration in total\\):'\nstdout ''\nstdout '  -- analyzing version 2'\nstdout '    -- data dependent changes detected:'\nstdout '      -- L1: Adding a non-nullable \"text\" column \"name\" will fail in case table \"users\" is not'\nstdout '         empty https://atlasgo.io/lint/analyzers#MF103'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -------------------------'\nstdout '  -- .+'\nstdout '  -- 1 version with warnings'\nstdout '  -- 2 schema changes'\nstdout '  -- 1 diagnostic'\n\n# Ignore entire file.\natlas migrate lint --dir file://migrations4 --dev-url URL --latest=1\nstdout ''\n\n# Ignore destructive changes globally.\natlas migrate lint --dir file://migrations5 --dev-url URL --latest=1\nstdout 'Analyzing changes from version 1 to 2 \\(1 migration in total\\):'\nstdout ''\nstdout '  -- analyzing version 2'\nstdout '    -- data dependent changes detected:'\nstdout '      -- L4: Adding a non-nullable \"text\" column \"name\" will fail in case table \"users\" is not'\nstdout '         empty https://atlasgo.io/lint/analyzers#MF103'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -------------------------'\nstdout '  -- .+'\nstdout '  -- 1 version with warnings'\nstdout '  -- 2 schema changes'\nstdout '  -- 1 diagnostic'\n\n# Ignore multiple change codes globally.\natlas migrate lint --dir file://migrations6 --dev-url URL --latest=1\nstdout 'Analyzing changes from version 1 to 2 \\(1 migration in total\\):'\nstdout ''\nstdout '  -- analyzing version 2'\nstdout '    -- no diagnostics found'\nstdout '  -- ok (.+)'\nstdout ''\nstdout '  -------------------------'\nstdout '  -- .+'\nstdout '  -- 1 version ok'\nstdout '  -- 2 schema changes'\n\n-- migrations1/1.sql --\nCREATE TABLE users (id int);\nCREATE TABLE pets (id int);\n\n-- migrations1/2.sql --\n\n-- atlas:nolint\nALTER TABLE users ADD COLUMN name text NOT NULL;\n\n-- atlas:nolint\nDROP TABLE pets;\n\n-- migrations2/1.sql --\nCREATE TABLE users (id int);\nCREATE TABLE pets (id int);\n\n-- migrations2/2.sql --\n\n-- atlas:nolint data_depend\nALTER TABLE users ADD COLUMN name text NOT NULL;\n\n-- atlas:nolint destructive\nDROP TABLE pets;\n\n-- migrations3/1.sql --\nCREATE TABLE users (id int);\nCREATE TABLE pets (id int);\n\n-- migrations3/2.sql --\nALTER TABLE users ADD COLUMN name text NOT NULL;\n-- atlas:nolint DS102\nDROP TABLE pets;\n\n-- migrations4/1.sql --\nCREATE TABLE users (id int);\nCREATE TABLE pets (id int);\n\n-- migrations4/2.sql --\n-- atlas:nolint\n\nDROP TABLE pets;\nALTER TABLE users ADD COLUMN name text NOT NULL;\n\n-- migrations5/1.sql --\nCREATE TABLE users (id int);\nCREATE TABLE pets (id int);\n\n-- migrations5/2.sql --\n-- atlas:nolint destructive\n\nDROP TABLE pets;\nALTER TABLE users ADD COLUMN name text NOT NULL;\n\n-- migrations6/1.sql --\nCREATE TABLE users (id int);\nCREATE TABLE pets (id int);\n\n-- migrations6/2.sql --\n-- atlas:nolint destructive data_depend\n\nDROP TABLE pets;\nALTER TABLE users ADD COLUMN name text NOT NULL;\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-lint-minimal-env.txtar",
    "content": "# Expect the command to fail; exit code 1.\n! atlas migrate lint --env local --latest=2\nstdout 'Analyzing changes until version 2 \\(2 migrations in total\\):'\nstdout ''\nstdout '  -- analyzing version 1'\nstdout '    -- no diagnostics found'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -- analyzing version 2'\nstdout '    -- destructive changes detected:'\nstdout '      -- L1: Dropping table \"users\" https://atlasgo.io/lint/analyzers#DS102'\nstdout '    -- suggested fix:'\nstdout '      -> Add a pre-migration check to ensure table \"users\" is empty before dropping it'\nstdout '  -- ok \\(.+\\)'\nstdout ''\nstdout '  -------------------------'\nstdout '  -- .+'\nstdout '  -- 1 version ok, 1 with errors'\nstdout '  -- 2 schema changes'\nstdout '  -- 1 diagnostic'\n\n\n-- atlas.hcl --\nenv \"local\" {\n    dev = \"URL\"\n}\n-- migrations/1.sql --\nCREATE TABLE users (id int);\n-- migrations/2.sql --\nDROP TABLE users;\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-lint-project.txtar",
    "content": "atlas migrate lint --dir file://migrations --dev-url URL --env=log_name > got.txt\ncmp got.txt expected1.txt\n\natlas migrate lint --dir file://migrations --dev-url URL --env=log_count > got.txt\ncmp got.txt expected2.txt\n\n-- migrations/1.sql --\nCREATE TABLE users (id int);\n\nCREATE TABLE pets (id int);\n\nALTER TABLE users RENAME COLUMN id TO oid;\n\n-- migrations/2.sql --\nDROP TABLE users;\n\n-- migrations/3.sql --\nDROP TABLE pets;\n\n-- expected1.txt --\n3.sql\n-- expected2.txt --\n2\n-- atlas.hcl --\nlint {\n    latest = 1\n    destructive {\n        error = false\n    }\n}\n\nenv \"log_name\" {\n    lint {\n        log = \"{{ range .Files }}{{ println .Name }}{{ end }}\"\n    }\n}\n\nenv \"log_count\" {\n    lint {\n        latest = 2\n        log = \"{{ len .Files | println }}\"\n    }\n}"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-project-multifile.txtar",
    "content": "atlas migrate diff --env local\ncmpmig 0 diff.sql\n\n# reset\nexec rm -rf migrations\n\natlas migrate diff --env src_list\ncmpmig 0 diff.sql\n\n# reset\nexec rm -rf migrations\n\natlas migrate diff --env single_elem\ncmpmig 0 diff.sql\n-- atlas.hcl --\nenv \"local\" {\n    url = \"URL\"\n    dev = \"sqlite://test?mode=memory&_fk=1\"\n    src = \"./schema\"\n    migration {\n        dir = \"file://migrations\"\n        format = atlas\n    }\n}\nenv \"src_list\" {\n    url = \"URL\"\n    dev = \"sqlite://test?mode=memory&_fk=1\"\n    src = [\n        \"./schema/1.hcl\",\n        \"./schema/2.hcl\",\n    ]\n    migration {\n        dir = \"file://migrations\"\n        format = atlas\n    }\n}\nenv \"single_elem\" {\n    url = \"URL\"\n    dev = \"sqlite://test?mode=memory&_fk=1\"\n    src = [\n        \"./schema/\",\n    ]\n    migration {\n        dir = \"file://migrations\"\n        format = atlas\n    }\n}\n-- schema/1.hcl --\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\n-- schema/2.hcl --\nschema \"main\" {\n}\n-- diff.sql --\n-- Create \"users\" table\nCREATE TABLE `users` (`id` int NOT NULL);\n-- empty.sql --\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-project.txtar",
    "content": "exec mkdir migrations\natlas migrate diff --env local\ncmpmig 0 diff.sql\n\natlas migrate validate --env local\n\natlas migrate new 1 --env local\ncmpmig 1 empty.sql\n\nexec touch migrations/2.sql\n! atlas migrate validate --env local\nstderr 'Error: checksum mismatch'\n\natlas migrate hash --env local\natlas migrate validate --env local\n\n-- atlas.hcl --\nenv \"local\" {\n    url = \"URL\"\n    dev = \"sqlite://test?mode=memory&_fk=1\"\n    src = \"./1.hcl\"\n    migration {\n        dir = \"file://migrations\"\n        format = atlas\n    }\n}\n-- 1.hcl --\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nschema \"main\" {\n}\n-- diff.sql --\n-- Create \"users\" table\nCREATE TABLE `users` (`id` int NOT NULL);\n-- empty.sql --\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-migrate-set.txtar",
    "content": "! atlas migrate set 0\nstderr 'Error: checksum file not found'\nstdout 'You have a checksum error in your migration directory.'\n\natlas migrate hash\n\n! atlas migrate set --url URL\nstderr 'Error: accepts 1 arg\\(s\\), received 0'\n\n! atlas migrate set --url URL foo bar\nstderr 'Error: accepts 1 arg\\(s\\), received 2'\n\n# Works on fresh database.\natlas migrate set 1 --url URL\natlas migrate apply 1 --url URL --dry-run\nstdout 'Migrating to version 2 from 1'\n\n# Set to second last migration.\natlas migrate set 2 --url URL\natlas migrate apply 1 --url URL --dry-run\nstdout 'Migrating to version 3 from 2'\n\n# Have one migration applied, manual do second, set revision and continue apply.\nclearSchema\natlas migrate apply 1 --url URL\nstdout 'Migrating to version 1'\natlas migrate set 2 --url URL\natlas migrate apply 1 --url URL --dry-run\nstdout 'Migrating to version 3 from 2'\n\n# Set to non-existing migration requires flag.\n! atlas migrate set 4 --url URL\nstderr 'Error: migration with version \"4\" not found'\n\n# If set to last version, nothing to do.\natlas migrate set 3 --url URL\natlas migrate apply --url URL\nstdout 'No migration files to execute'\n\n# Partially applied (error), fix with set.\nclearSchema\nmv broken.sql migrations/4.sql\natlas migrate hash\n! atlas migrate apply --url URL --tx-mode none\nstdout 'Migrating to version 4'\natlas migrate set 4 --url URL\natlas migrate apply --url URL\nstdout 'No migration files to execute'\n\n-- migrations/1_first.sql --\nCREATE TABLE `users` (`id` bigint NOT NULL, `age` bigint NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`));\n\n-- migrations/2_second.sql --\nALTER TABLE `users` ADD UNIQUE INDEX `age` (`age`);\n\n-- migrations/3_third.sql --\nCREATE TABLE `pets` (`id` bigint NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`));\n\n-- broken.sql --\nCREATE TABLE `vets` (`id` bigint NOT NULL, `name` varchar(255) NOT NULL, PRIMARY KEY(`id`));\nasdf ALTER TABLE `users` ADD UNIQUE INDEX `name` (`name`);\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-project-vars.txtar",
    "content": "! atlas schema apply --env local --auto-approve\nstderr 'Error: missing value for required variable \"user_status_default\"'\n\natlas schema apply --env local --auto-approve --var user_status_default=hello\ncmpshow users expected.sql\n\n-- atlas.hcl --\nvariable \"user_status_default\" {\n    type = string\n}\nenv \"local\" {\n    url = \"URL\"\n    src = \"./1.hcl\"\n    def_val = var.user_status_default\n}\n-- 1.hcl --\nvariable \"def_val\" {\n    type = string\n}\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"status\" {\n    null = true\n    type = text\n    default = var.def_val\n  }\n}\nschema \"main\" {\n}\n-- expected.sql --\nCREATE TABLE `users` (\n  `id` int NOT NULL,\n  `status` text NULL DEFAULT 'hello'\n)"
  },
  {
    "path": "internal/integration/testdata/sqlite/cli-schema-project-file.txtar",
    "content": "! atlas schema inspect\nstderr '\"url\" not set'\n\n! atlas schema apply -f 1.hcl\nstderr '\"url\" not set'\n\n! atlas schema apply --url URL\nstderr 'one of flag\\(s\\) \"file\" or \"to\" is required'\n\n! atlas schema apply -f atlas.hcl -u URL\nstderr 'cannot parse project file'\n\n# Verify \"url\" and \"src\" attributes of the env are used.\natlas schema apply --env local --auto-approve\natlas schema inspect --env local > inspected.hcl\ncmp 1.hcl inspected.hcl\n\n# Verify the precedence of flag over project file.\natlas schema apply --env local --auto-approve -f 2.hcl\natlas schema inspect --env local > inspected.hcl\ncmp 2.hcl inspected.hcl\n\n-- atlas.hcl --\nenv \"local\" {\n    url = \"URL\"\n    src = \"./1.hcl\"\n}\n-- 1.hcl --\ntable \"users\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nschema \"main\" {\n}\n-- 2.hcl --\ntable \"other\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nschema \"main\" {\n}"
  },
  {
    "path": "internal/integration/testdata/sqlite/column-default.txtar",
    "content": "execsql 'CREATE TABLE tbl (col)'\ncmphcl 1.hcl\n\n-- 1.hcl --\ntable \"tbl\" {\n  schema = schema.main\n  column \"col\" {\n    null = true\n    type = blob\n  }\n}\nschema \"main\" {\n}\n"
  },
  {
    "path": "internal/integration/testdata/sqlite/column-generated.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\n# Insert a few records to the table, and check the\n# migration process using a temporary table.\nexecsql 'INSERT INTO users (a) VALUES (1), (2), (3)'\n\napply 2.hcl\ncmpshow users 2.sql\n\napply 3.hcl\ncmpshow users 3.sql\n\n# Appending a new VIRTUAL column should use ALTER command.\napply 4.hcl\ncmpshow users 4.sql\n\n\n-- 1.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n    schema = schema.main\n    column \"a\" {\n        type = int\n    }\n    column \"b\" {\n        type = int\n        as = \"1\"\n    }\n    column \"c\" {\n        type = int\n        as {\n            expr = \"2\"\n            type = STORED\n        }\n    }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (`a` int NOT NULL, `b` int NOT NULL AS (1) VIRTUAL, `c` int NOT NULL AS (2) STORED)\n\n-- 2.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n    schema = schema.main\n    column \"a\" {\n        type = int\n    }\n    column \"b\" {\n        type = int\n        as = \"1\"\n    }\n    column \"c\" {\n        type = int\n        as {\n            expr = \"2\"\n            type = VIRTUAL\n        }\n    }\n}\n\n-- 2.sql --\nCREATE TABLE \"users\" (`a` int NOT NULL, `b` int NOT NULL AS (1) VIRTUAL, `c` int NOT NULL AS (2) VIRTUAL)\n\n-- 3.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n    schema = schema.main\n    column \"a\" {\n        type = int\n    }\n    column \"b\" {\n        type = int\n        as = \"2\"\n    }\n    column \"c\" {\n        type = int\n        as {\n            expr = \"3\"\n            type = VIRTUAL\n        }\n    }\n}\n\n-- 3.sql --\nCREATE TABLE \"users\" (`a` int NOT NULL, `b` int NOT NULL AS (2) VIRTUAL, `c` int NOT NULL AS (3) VIRTUAL)\n\n-- 4.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n    schema = schema.main\n    column \"a\" {\n        type = int\n    }\n    column \"b\" {\n        type = int\n        as = \"2\"\n    }\n    column \"c\" {\n        type = int\n        as {\n            expr = \"3\"\n            type = VIRTUAL\n        }\n    }\n    column \"d\" {\n        type = int\n        as {\n            expr = \"4\"\n            type = VIRTUAL\n        }\n    }\n}\n\n-- 4.sql --\nCREATE 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)"
  },
  {
    "path": "internal/integration/testdata/sqlite/column-user-defined.txtar",
    "content": "# Initial changes.\natlas schema apply --url URL --dev-url DEV_URL --to file://schema.v1.hcl --auto-approve\natlas schema apply --url URL --dev-url DEV_URL --to file://schema.v1.hcl --auto-approve\nstdout 'Schema is synced, no changes to be made'\natlas schema inspect --url URL > got\ncmp schema.v1.hcl.inspected got\n\n# Changing user defined type.\natlas schema apply --url URL --dev-url DEV_URL --to file://schema.v2.hcl --auto-approve\natlas schema apply --url URL --dev-url DEV_URL --to file://schema.v2.hcl --auto-approve\nstdout 'Schema is synced, no changes to be made'\natlas schema inspect --url URL > got\ncmp schema.v2.hcl.inspected got\n\n-- schema.v1.hcl --\ntable \"t\" {\n  schema = schema.main\n  column \"c\" {\n    null = true\n    type = sql(\"USER_DEFINED\")\n  }\n}\nschema \"main\" {\n}\n-- schema.v1.hcl.inspected --\ntable \"t\" {\n  schema = schema.main\n  column \"c\" {\n    null = true\n    type = sql(\"USER_DEFINED\")\n  }\n}\nschema \"main\" {\n}\n-- schema.v2.hcl --\ntable \"t\" {\n  schema = schema.main\n  column \"c\" {\n    null = true\n    type = sql(\"USER_TYPE\")\n  }\n}\nschema \"main\" {\n}\n-- schema.v2.hcl.inspected --\ntable \"t\" {\n  schema = schema.main\n  column \"c\" {\n    null = true\n    type = sql(\"USER_TYPE\")\n  }\n}\nschema \"main\" {\n}"
  },
  {
    "path": "internal/integration/testdata/sqlite/index-desc.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\n# Drop the \"DESC\" option from the key part.\napply 2.hcl\ncmpshow users 2.sql\n# Use of \"columns\" instead of \"on\" should not trigger a change.\nsynced 2-no-change.hcl\n\napply 3.hcl\ncmpshow users 3.sql\n\n-- 1.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n    schema = schema.main\n    column \"rank\" {\n        type = int\n    }\n    index \"rank_idx\" {\n        on {\n            desc   = true\n            column = table.users.column.rank\n        }\n    }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (`rank` int NOT NULL)\nCREATE INDEX `rank_idx` ON `users` (`rank` DESC)\n\n-- 2.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n    schema = schema.main\n    column \"rank\" {\n        type = int\n    }\n    index \"rank_idx\" {\n        on {\n            column = table.users.column.rank\n        }\n    }\n}\n\n-- 2.sql --\nCREATE TABLE \"users\" (`rank` int NOT NULL)\nCREATE INDEX `rank_idx` ON `users` (`rank`)\n\n-- 2-no-change.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n    schema = schema.main\n    column \"rank\" {\n        type = int\n    }\n    index \"rank_idx\" {\n        columns = [\n            table.users.column.rank,\n        ]\n    }\n}\n\n-- 3.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n    schema = schema.main\n    column \"rank\" {\n        type = int\n    }\n    column \"score\" {\n        type = int\n    }\n    index \"rank_score_idx\" {\n        on {\n            column = table.users.column.rank\n        }\n        on {\n            column = table.users.column.score\n            desc = true\n        }\n    }\n}\n\n-- 3.sql --\nCREATE TABLE \"users\" (`rank` int NOT NULL, `score` int NOT NULL)\nCREATE INDEX `rank_score_idx` ON `users` (`rank`, `score` DESC)"
  },
  {
    "path": "internal/integration/testdata/sqlite/index-expr.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n  schema = schema.main\n  column \"first_name\" {\n    null = false\n    type = text\n  }\n  column \"last_name\" {\n    null = false\n    type = text\n  }\n  index \"full_name\" {\n    on {\n        expr = \"first_name || ' ' || last_name\"\n    }\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (`first_name` text NOT NULL, `last_name` text NOT NULL)\nCREATE INDEX `full_name` ON `users` ((first_name || ' ' || last_name))\n\n-- 2.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n  schema = schema.main\n  column \"first_name\" {\n    null = false\n    type = text\n  }\n  index \"full_name\" {\n    on {\n        expr = \"lower(first_name) || '''s first name'\"\n    }\n  }\n}\n\n-- 2.sql --\nCREATE TABLE \"users\" (`first_name` text NOT NULL)\nCREATE INDEX `full_name` ON `users` ((lower(first_name) || '''s first name'))"
  },
  {
    "path": "internal/integration/testdata/sqlite/index-partial.txtar",
    "content": "apply 1.hcl\ncmpshow users 1.sql\n\napply 2.hcl\ncmpshow users 2.sql\n\n-- 1.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n  schema = schema.main\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"active\" {\n    null = true\n    type = boolean\n  }\n  index \"users_name\" {\n    columns = [column.name]\n    where = \"active\"\n  }\n}\n\n-- 1.sql --\nCREATE TABLE `users` (`name` text NOT NULL, `active` boolean NULL)\nCREATE INDEX `users_name` ON `users` (`name`) WHERE active\n\n-- 2.hcl --\nschema \"main\" {}\n\ntable \"users\" {\n  schema = schema.main\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"active\" {\n    null = true\n    type = boolean\n  }\n  index \"users_name\" {\n    columns = [column.name]\n    where = \"active AND name <> ''\"\n  }\n}\n\n-- 2.sql --\nCREATE TABLE \"users\" (`name` text NOT NULL, `active` boolean NULL)\nCREATE INDEX `users_name` ON `users` (`name`) WHERE active AND name <> ''"
  },
  {
    "path": "internal/integration/testdata/sqlite/table-options.txtar",
    "content": "apply 1.hcl\ncmpshow t1 1.sql\ncmpshow t2 2.sql\ncmpshow t3 3.sql\n\n# Drop options.\napply 2.hcl\ncmpshow t1 11.sql\n\n-- 1.hcl --\nschema \"main\" {}\n\ntable \"t1\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = integer\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n  strict = true\n  without_rowid = true\n}\n\ntable \"t2\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = integer\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n  strict = true\n}\n\ntable \"t3\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = integer\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n  without_rowid = true\n}\n\n-- 1.sql --\nCREATE TABLE `t1` (`id` integer NOT NULL, PRIMARY KEY (`id`)) WITHOUT ROWID, STRICT\n\n-- 2.sql --\nCREATE TABLE `t2` (`id` integer NOT NULL, PRIMARY KEY (`id`)) STRICT\n\n-- 3.sql --\nCREATE TABLE `t3` (`id` integer NOT NULL, PRIMARY KEY (`id`)) WITHOUT ROWID\n\n-- 2.hcl --\nschema \"main\" {}\n\ntable \"t1\" {\n  schema = schema.main\n  column \"id\" {\n    null = false\n    type = integer\n  }\n  primary_key  {\n    columns = [column.id]\n  }\n}\n\n-- 11.sql --\nCREATE TABLE \"t1\" (`id` integer NOT NULL, PRIMARY KEY (`id`))\n"
  },
  {
    "path": "internal/integration/tidb_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage integration\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"log\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/mysql\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t_ \"github.com/go-sql-driver/mysql\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nvar tidbTests = map[string]*myTest{\n\t\"tidb5\": {port: 4309},\n\t\"tidb6\": {port: 4310},\n}\n\nfunc tidbRun(t *testing.T, fn func(*myTest)) {\n\tfor version, tt := range tidbTests {\n\t\tif flagVersion == \"\" || flagVersion == version {\n\t\t\tt.Run(version, func(t *testing.T) {\n\t\t\t\ttt.once.Do(func() {\n\t\t\t\t\tvar err error\n\t\t\t\t\ttt.version = version\n\t\t\t\t\ttt.rrw = &rrw{}\n\t\t\t\t\ttt.db, err = sql.Open(\"mysql\", fmt.Sprintf(\"root@tcp(localhost:%d)/test?parseTime=True\", tt.port))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Fatalln(err)\n\t\t\t\t\t}\n\t\t\t\t\tdbs = append(dbs, tt.db) // close connection after all tests have been run\n\t\t\t\t\ttt.drv, err = mysql.Open(tt.db)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Fatalln(err)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\ttt := &myTest{T: t, db: tt.db, drv: tt.drv, version: version, port: tt.port, rrw: tt.rrw}\n\t\t\t\tfn(tt)\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc TestTiDB_AddDropTable(t *testing.T) {\n\ttidbRun(t, func(t *myTest) {\n\t\ttestAddDrop(t)\n\t})\n}\n\nfunc TestTiDB_Relation(t *testing.T) {\n\ttidbRun(t, func(t *myTest) {\n\t\ttestRelation(t)\n\t})\n}\n\nfunc TestTiDB_AddIndexedColumns(t *testing.T) {\n\ttidbRun(t, func(t *myTest) {\n\t\tusersT := &schema.Table{\n\t\t\tName:    \"users\",\n\t\t\tColumns: []*schema.Column{{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}}},\n\t\t}\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tt.dropTables(usersT.Name)\n\t\tusersT.Columns = append(usersT.Columns, &schema.Column{\n\t\t\tName:    \"a\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.RawExpr{X: \"10\"},\n\t\t}, &schema.Column{\n\t\t\tName:    \"b\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.RawExpr{X: \"10\"},\n\t\t}, &schema.Column{\n\t\t\tName:    \"c\",\n\t\t\tType:    &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\tDefault: &schema.RawExpr{X: \"10\"},\n\t\t})\n\t\tparts := usersT.Columns[len(usersT.Columns)-3:]\n\t\tusersT.Indexes = append(usersT.Indexes, &schema.Index{\n\t\t\tUnique: true,\n\t\t\tName:   \"a_b_c_unique\",\n\t\t\tParts:  []*schema.IndexPart{{C: parts[0]}, {C: parts[1]}, {C: parts[2]}},\n\t\t})\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.NotEmpty(t, changes, \"usersT contains 2 new columns and 1 new index\")\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\n\t\t// In MySQL, dropping a column should remove it from the key.\n\t\t// However, on TiDB an explicit DROP/ADD INDEX is required.\n\t\tidx, ok := usersT.Index(\"a_b_c_unique\")\n\t\trequire.True(t, ok)\n\t\tidx.Parts = idx.Parts[:len(idx.Parts)-1]\n\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, t.loadUsers())\n\n\t\t// Dropping a column from both table and index.\n\t\tusersT = t.loadUsers()\n\t\tidx, ok = usersT.Index(\"a_b_c_unique\")\n\t\trequire.True(t, ok)\n\t\trequire.Len(t, idx.Parts, 2)\n\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\tidx.Parts = idx.Parts[:len(idx.Parts)-1]\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 2)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, t.loadUsers())\n\n\t\t// Dropping a column should remove\n\t\t// single-column keys as well.\n\t\tusersT = t.loadUsers()\n\t\tidx, ok = usersT.Index(\"a_b_c_unique\")\n\t\trequire.True(t, ok)\n\t\trequire.Len(t, idx.Parts, 1)\n\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\t// In MySQL, dropping a column should remove its index.\n\t\t// However, on TiDB an explicit DROP INDEX is required.\n\t\tusersT.Indexes = nil\n\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 2)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, t.loadUsers())\n\t\t_, ok = t.loadUsers().Index(\"a_b_c_unique\")\n\t\trequire.False(t, ok)\n\t})\n}\n\nfunc TestTiDB_AddColumns(t *testing.T) {\n\ttidbRun(t, func(t *myTest) {\n\t\tusersT := t.users()\n\t\tt.dropTables(usersT.Name)\n\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\tusersT.Columns = append(\n\t\t\tusersT.Columns,\n\t\t\t&schema.Column{Name: \"a\", Type: &schema.ColumnType{Raw: \"tinyblob\", Type: &schema.BinaryType{T: \"tinyblob\"}}},\n\t\t\t&schema.Column{Name: \"b\", Type: &schema.ColumnType{Raw: \"mediumblob\", Type: &schema.BinaryType{T: \"mediumblob\"}}},\n\t\t\t&schema.Column{Name: \"c\", Type: &schema.ColumnType{Raw: \"blob\", Type: &schema.BinaryType{T: \"blob\"}}},\n\t\t\t&schema.Column{Name: \"d\", Type: &schema.ColumnType{Raw: \"longblob\", Type: &schema.BinaryType{T: \"longblob\"}}},\n\t\t\t&schema.Column{Name: \"e\", Type: &schema.ColumnType{Raw: \"binary\", Type: &schema.BinaryType{T: \"binary\"}}},\n\t\t\t&schema.Column{Name: \"f\", Type: &schema.ColumnType{Raw: \"varbinary(255)\", Type: &schema.BinaryType{T: \"varbinary(255)\"}}, Default: &schema.Literal{V: \"foo\"}},\n\t\t\t&schema.Column{Name: \"g\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar\", Size: 255}}},\n\t\t\t&schema.Column{Name: \"h\", Type: &schema.ColumnType{Raw: \"varchar(255)\", Type: &schema.StringType{T: \"varchar(255)\"}}},\n\t\t\t&schema.Column{Name: \"i\", Type: &schema.ColumnType{Raw: \"tinytext\", Type: &schema.StringType{T: \"tinytext\"}}},\n\t\t\t&schema.Column{Name: \"j\", Type: &schema.ColumnType{Raw: \"mediumtext\", Type: &schema.StringType{T: \"mediumtext\"}}},\n\t\t\t&schema.Column{Name: \"k\", Type: &schema.ColumnType{Raw: \"text\", Type: &schema.StringType{T: \"text\"}}},\n\t\t\t&schema.Column{Name: \"l\", Type: &schema.ColumnType{Raw: \"longtext\", Type: &schema.StringType{T: \"longtext\"}}},\n\t\t\t&schema.Column{Name: \"m\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\", Precision: 10, Scale: 6}}},\n\t\t\t&schema.Column{Name: \"m1\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\"}}},\n\t\t\t&schema.Column{Name: \"m2\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\", Precision: 2}}},\n\t\t\t&schema.Column{Name: \"n\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 10, Scale: 2}}},\n\t\t\t&schema.Column{Name: \"n1\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\"}}},\n\t\t\t&schema.Column{Name: \"n2\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 2}}},\n\t\t\t&schema.Column{Name: \"o\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"float\", Precision: 2}}},\n\t\t\t&schema.Column{Name: \"p\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"double\", Precision: 14}}},\n\t\t\t&schema.Column{Name: \"q\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"real\", Precision: 14}}},\n\t\t\t&schema.Column{Name: \"r\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t&schema.Column{Name: \"s\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t&schema.Column{Name: \"t\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"smallint\"}}},\n\t\t\t&schema.Column{Name: \"u\", Type: &schema.ColumnType{Type: &schema.EnumType{T: \"enum\", Values: []string{\"a\", \"b\", \"c\"}}}},\n\t\t\t&schema.Column{Name: \"v\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"char(36)\"}}},\n\t\t\t&schema.Column{Name: \"x\", Type: &schema.ColumnType{Type: &schema.SpatialType{T: \"line\"}}},\n\t\t\t&schema.Column{Name: \"z\", Type: &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp\"}}, Default: &schema.RawExpr{X: \"CURRENT_TIMESTAMP\"}},\n\t\t)\n\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\trequire.Len(t, changes, 27)\n\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\tensureNoChange(t, usersT)\n\t})\n}\n\nfunc TestTiDB_ColumnInt(t *testing.T) {\n\tt.Run(\"ChangeType\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}}},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tfor _, typ := range []string{\"tinyint\", \"smallint\", \"mediumint\", \"bigint\"} {\n\t\t\t\tusersT.Columns[0].Type.Type = &schema.IntegerType{T: typ}\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t}\n\t\t})\n\t})\n\n\tt.Run(\"ChangeDefault\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}, Default: &schema.RawExpr{X: \"1\"}}},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t\tfor _, x := range []string{\"2\", \"'3'\", \"10.1\"} {\n\t\t\t\tusersT.Columns[0].Default.(*schema.RawExpr).X = x\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t}\n\t\t})\n\t})\n}\n\nfunc TestTiDB_ColumnString(t *testing.T) {\n\tt.Run(\"ChangeType\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(20)\"}}}},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tfor _, typ := range []string{\"varchar(255)\", \"char(120)\", \"tinytext\", \"mediumtext\", \"longtext\"} {\n\t\t\t\tusersT.Columns[0].Type.Type = &schema.StringType{T: typ}\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t}\n\t\t})\n\t})\n\n\tt.Run(\"AddWithDefault\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(255)\"}}, Default: &schema.RawExpr{X: \"hello\"}},\n\t\t\t\t\t{Name: \"b\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"char(255)\"}}, Default: &schema.RawExpr{X: \"'world'\"}},\n\t\t\t\t},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"ChangeDefault\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName:    \"users\",\n\t\t\t\tColumns: []*schema.Column{{Name: \"a\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(255)\"}}, Default: &schema.RawExpr{X: \"hello\"}}},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t\tfor _, x := range []string{\"2\", \"'3'\", \"'world'\"} {\n\t\t\t\tusersT.Columns[0].Default.(*schema.RawExpr).X = x\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t}\n\t\t})\n\t})\n}\n\nfunc TestTiDB_ColumnBool(t *testing.T) {\n\tt.Run(\"Add\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}},\n\t\t\t\t\t{Name: \"b\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}}},\n\t\t\t\t\t{Name: \"c\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"tinyint\"}}},\n\t\t\t\t\t{Name: \"d\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"tinyint(1)\"}}},\n\t\t\t\t},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"AddWithDefault\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"1\"}},\n\t\t\t\t\t{Name: \"b\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"0\"}},\n\t\t\t\t\t{Name: \"c\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"'1'\"}},\n\t\t\t\t\t{Name: \"d\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"'0'\"}},\n\t\t\t\t\t{Name: \"e\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"true\"}},\n\t\t\t\t\t{Name: \"f\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"false\"}},\n\t\t\t\t\t{Name: \"g\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"TRUE\"}},\n\t\t\t\t\t{Name: \"h\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"FALSE\"}},\n\t\t\t\t},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"ChangeDefault\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}, Default: &schema.RawExpr{X: \"1\"}},\n\t\t\t\t},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t\t// Change default from \"true\" to \"false\" to \"true\".\n\t\t\tfor _, x := range []string{\"false\", \"true\"} {\n\t\t\t\tusersT.Columns[0].Default.(*schema.RawExpr).X = x\n\t\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\t\trequire.Len(t, changes, 1)\n\t\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\t\tensureNoChange(t, usersT)\n\t\t\t}\n\t\t})\n\t})\n\n\tt.Run(\"ChangeNull\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT := &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}, Null: true}},\n\t\t\t\t},\n\t\t\t}\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tensureNoChange(t, usersT)\n\t\t\tusersT.Columns[0].Type.Null = false\n\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 1)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n}\n\nfunc TestTiDB_ForeignKey(t *testing.T) {\n\tt.Run(\"ChangeAction\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT, postsT := t.users(), t.posts()\n\t\t\tt.dropTables(postsT.Name, usersT.Name)\n\t\t\tt.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})\n\t\t\tensureNoChange(t, postsT, usersT)\n\n\t\t\tpostsT = t.loadPosts()\n\t\t\tfk, ok := postsT.ForeignKey(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tfk.OnUpdate = schema.SetNull\n\t\t\tfk.OnDelete = schema.Cascade\n\t\t\tchanges := t.diff(t.loadPosts(), postsT)\n\t\t\trequire.Len(t, changes, 1)\n\t\t\tmodifyF, ok := changes[0].(*schema.ModifyForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)\n\n\t\t\tt.migrate(&schema.ModifyTable{T: postsT, Changes: changes})\n\t\t\tensureNoChange(t, postsT, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"UnsetNull\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT, postsT := t.users(), t.posts()\n\t\t\tt.dropTables(postsT.Name, usersT.Name)\n\t\t\tfk, ok := postsT.ForeignKey(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tfk.OnDelete = schema.SetNull\n\t\t\tfk.OnUpdate = schema.SetNull\n\t\t\tt.migrate(&schema.AddTable{T: usersT}, &schema.AddTable{T: postsT})\n\t\t\tensureNoChange(t, postsT, usersT)\n\n\t\t\tpostsT = t.loadPosts()\n\t\t\tc, ok := postsT.Column(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tc.Type.Null = false\n\t\t\tfk, ok = postsT.ForeignKey(\"author_id\")\n\t\t\trequire.True(t, ok)\n\t\t\tfk.OnUpdate = schema.NoAction\n\t\t\tfk.OnDelete = schema.NoAction\n\t\t\tchanges := t.diff(t.loadPosts(), postsT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\tmodifyC, ok := changes[0].(*schema.ModifyColumn)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyC.Change == schema.ChangeNull)\n\t\t\tmodifyF, ok := changes[1].(*schema.ModifyForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.True(t, modifyF.Change == schema.ChangeUpdateAction|schema.ChangeDeleteAction)\n\n\t\t\tt.migrate(&schema.ModifyTable{T: postsT, Changes: changes})\n\t\t\tensureNoChange(t, postsT, usersT)\n\t\t})\n\t})\n\n\tt.Run(\"AddDrop\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tusersT := t.users()\n\t\t\tt.dropTables(usersT.Name)\n\t\t\tt.migrate(&schema.AddTable{T: usersT})\n\t\t\tensureNoChange(t, usersT)\n\n\t\t\t// Add foreign key.\n\t\t\tusersT.Columns = append(usersT.Columns, &schema.Column{\n\t\t\t\tName: \"spouse_id\",\n\t\t\t\tType: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true},\n\t\t\t})\n\t\t\tusersT.ForeignKeys = append(usersT.ForeignKeys, &schema.ForeignKey{\n\t\t\t\tSymbol:     \"spouse_id\",\n\t\t\t\tTable:      usersT,\n\t\t\t\tColumns:    usersT.Columns[len(usersT.Columns)-1:],\n\t\t\t\tRefTable:   usersT,\n\t\t\t\tRefColumns: usersT.Columns[:1],\n\t\t\t\tOnDelete:   schema.NoAction,\n\t\t\t})\n\n\t\t\tchanges := t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\taddC, ok := changes[0].(*schema.AddColumn)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, \"spouse_id\", addC.C.Name)\n\t\t\taddF, ok := changes[1].(*schema.AddForeignKey)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, \"spouse_id\", addF.F.Symbol)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\n\t\t\t// Drop foreign keys.\n\t\t\tusersT.Columns = usersT.Columns[:len(usersT.Columns)-1]\n\t\t\tusersT.ForeignKeys = usersT.ForeignKeys[:len(usersT.ForeignKeys)-1]\n\t\t\tchanges = t.diff(t.loadUsers(), usersT)\n\t\t\trequire.Len(t, changes, 2)\n\t\t\tt.migrate(&schema.ModifyTable{T: usersT, Changes: changes})\n\t\t\tensureNoChange(t, usersT)\n\t\t})\n\t})\n}\n\nfunc TestTiDB_HCL_Realm(t *testing.T) {\n\ttidbRun(t, func(t *myTest) {\n\t\tt.dropSchemas(\"second\")\n\t\trealm := t.loadRealm()\n\t\thcl, err := mysql.MarshalHCL(realm)\n\t\trequire.NoError(t, err)\n\t\twa := string(hcl) + `\nschema \"second\" {\n}\n`\n\t\tt.applyRealmHcl(wa)\n\t\trealm, err = t.drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\t\tMode: schema.InspectSchemas | schema.InspectTables,\n\t\t})\n\t\trequire.NoError(t, err)\n\t\t_, ok := realm.Schema(\"test\")\n\t\trequire.True(t, ok)\n\t\t_, ok = realm.Schema(\"second\")\n\t\trequire.True(t, ok)\n\t})\n}\n\nfunc TestTiDB_DefaultsHCL(t *testing.T) {\n\tn := \"atlas_defaults\"\n\ttidbRun(t, func(t *myTest) {\n\t\tddl := `\ncreate table atlas_defaults\n(\n\tstring varchar(255) default \"hello_world\",\n\tquoted varchar(100) default 'never say \"never\"',\n\ttBit bit(10) default b'10101',\n\tts timestamp default CURRENT_TIMESTAMP,\n\tnumber int default 42\n)\n`\n\t\tt.dropTables(n)\n\t\t_, err := t.db.Exec(ddl)\n\t\trequire.NoError(t, err)\n\t\trealm := t.loadRealm()\n\t\tspec, err := mysql.MarshalHCL(realm.Schemas[0])\n\t\trequire.NoError(t, err)\n\t\tvar s schema.Realm\n\t\terr = mysql.EvalHCLBytes(spec, &s, nil)\n\t\trequire.NoError(t, err)\n\t\tt.dropTables(n)\n\t\tt.applyHcl(string(spec))\n\t\tensureNoChange(t, realm.Schemas[0].Tables[0])\n\t})\n}\n\nfunc TestTiDB_CLI_MultiSchema(t *testing.T) {\n\th := `\n\t\t\tschema \"test\" {\n\t\t\t\tcharset   = \"%s\"\n\t\t\t\tcollation = \"%s\"\n\t\t\t}\n\t\t\ttable \"users\" {\n\t\t\t\tschema = schema.test\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = int\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [table.users.column.id]\n\t\t\t\t}\n\t\t\t}\n\t\t\tschema \"test2\" {\n\t\t\t\tcharset   = \"%s\"\n\t\t\t\tcollation = \"%s\"\n\t\t\t}\n\t\t\ttable \"users\" {\n\t\t\t\tschema = schema.test2\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = int\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [table.users.column.id]\n\t\t\t\t}\n\t\t\t}`\n\tt.Run(\"SchemaInspect\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tt.dropSchemas(\"test2\")\n\t\t\tt.dropTables(\"users\")\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLIMultiSchemaInspect(t, fmt.Sprintf(h, charset.V, collate.V, charset.V, collate.V), t.url(\"\"), []string{\"test\", \"test2\"}, mysql.EvalHCL)\n\t\t})\n\t})\n\tt.Run(\"SchemaApply\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tt.dropSchemas(\"test2\")\n\t\t\tt.dropTables(\"users\")\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLIMultiSchemaApply(t, fmt.Sprintf(h, charset.V, collate.V, charset.V, collate.V), t.url(\"\"), []string{\"test\", \"test2\"}, mysql.EvalHCL)\n\t\t})\n\t})\n}\n\nfunc TestTiDB_CLI(t *testing.T) {\n\th := `\n\t\t\tschema \"test\" {\n\t\t\t\tcharset   = \"%s\"\n\t\t\t\tcollation = \"%s\"\n\t\t\t}\n\t\t\ttable \"users\" {\n\t\t\t\tschema = schema.test\n\t\t\t\tcolumn \"id\" {\n\t\t\t\t\ttype = int\n\t\t\t\t}\n\t\t\t\tprimary_key {\n\t\t\t\t\tcolumns = [table.users.column.id]\n\t\t\t\t}\n\t\t\t}`\n\tt.Run(\"SchemaInspect\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLISchemaInspect(t, fmt.Sprintf(h, charset.V, collate.V), t.url(\"test\"), mysql.EvalHCL)\n\t\t})\n\t})\n\tt.Run(\"SchemaApply\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLISchemaApply(t, fmt.Sprintf(h, charset.V, collate.V), t.url(\"test\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyWithVars\", func(t *testing.T) {\n\t\th := `\nvariable \"tenant\" {\n\ttype = string\n}\nschema \"tenant\" {\n\tname = var.tenant\n}\ntable \"users\" {\n\tschema = schema.tenant\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n}\n`\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\ttestCLISchemaApply(t, h, t.url(\"test\"), \"--var\", \"tenant=test\")\n\t\t})\n\t})\n\tt.Run(\"SchemaApplyDryRun\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tattrs := t.defaultAttrs()\n\t\t\tcharset, collate := attrs[0].(*schema.Charset), attrs[1].(*schema.Collation)\n\t\t\ttestCLISchemaApplyDry(t, fmt.Sprintf(h, charset.V, collate.V), t.url(\"test\"))\n\t\t})\n\t})\n\tt.Run(\"SchemaDiffRun\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\ttestCLISchemaDiff(t, t.url(\"test\"))\n\t\t})\n\t})\n}\n\nfunc TestTiDB_HCL(t *testing.T) {\n\tfull := `\nschema \"test\" {\n}\ntable \"users\" {\n\tschema = schema.test\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tprimary_key {\n\t\tcolumns = [table.users.column.id]\n\t}\n}\ntable \"posts\" {\n\tschema = schema.test\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tcolumn \"author_id\" {\n\t\ttype = int\n\t}\n\tforeign_key \"author\" {\n\t\tcolumns = [\n\t\t\ttable.posts.column.author_id,\n\t\t]\n\t\tref_columns = [\n\t\t\ttable.users.column.id,\n\t\t]\n\t}\n\tprimary_key {\n\t\tcolumns = [table.users.column.id]\n\t}\n}\n`\n\tempty := `\nschema \"test\" {\n}\n`\n\ttidbRun(t, func(t *myTest) {\n\t\ttestHCLIntegration(t, full, empty)\n\t})\n}\n\nfunc TestTiDB_Sanity(t *testing.T) {\n\tn := \"atlas_types_sanity\"\n\tt.Run(\"Common\", func(t *testing.T) {\n\t\tddl := `\ncreate table atlas_types_sanity\n(\n    tBit                        bit(10)              default b'1000000001'                                       null,\n\t\ttInt                        int(10)              default 4                                               not null,\n\t\ttTinyInt                    tinyint(10)          default 8                                                   null,\n\t\ttSmallInt                   smallint(10)         default 2                                                   null,\n\t\ttMediumInt                  mediumint(10)        default 11                                                  null,\n\t\ttBigInt                     bigint(10)           default 4                                                   null,\n\t\ttDecimal                    decimal              default 4                                                   null,\n\t\ttNumeric                    numeric              default 4                                               not null,\n\t\ttFloat                      float         \t\t\t default 4                                                   null,\n\t\ttDouble                     double(10, 0)        default 4                                                   null,\n\t\ttReal                       double(10, 0)        default 4                                                   null,\n\t\ttTimestamp                  timestamp            default CURRENT_TIMESTAMP                                   null,\n\t\ttTimestampFraction          timestamp(6)         default CURRENT_TIMESTAMP(6)                                null,\n\t\ttTimestampOnUpdate          timestamp            default CURRENT_TIMESTAMP    ON UPDATE CURRENT_TIMESTAMP    null,\n\t\ttTimestampFractionOnUpdate  timestamp(6)         default CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) null,\n\t\ttDate                       date                                                                             null,\n\t\ttTime                       time                                                                             null,\n\t\ttDateTime                   datetime                                                                         null,\n\t\ttYear                       year                                                                             null,\n\t\ttVarchar                    varchar(10)          default 'Titan'                                             null,\n\t\ttChar                       char(25)             default 'Olimpia'                                       not null,\n\t\ttVarBinary                  varbinary(30)        default 'Titan'                                             null,\n\t\ttBinary                     binary(5)            default 'Titan'                                             null,\n\t\ttBlob                       blob(5)              default                                                     null,\n\t\ttTinyBlob                   tinyblob                                                                         null,\n\t\ttMediumBlob                 mediumblob           default                                                     null,\n\t\ttLongBlob                   longblob             default                                                     null,\n\t\ttText                       text(13)             default                                                     null,\n\t\ttTinyText                   tinytext             default                                                     null,\n\t\ttMediumText                 mediumtext           default                                                     null,\n\t\ttLongText                   longtext             default                                                     null,\n\t\ttEnum                       enum('a','b')        default                                                     null,\n\t\ttSet                        set('a','b')         default                                                     null\n) CHARSET = latin1;\n`\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tt.dropTables(n)\n\t\t\t_, err := t.db.Exec(ddl)\n\t\t\trequire.NoError(t, err)\n\t\t\trealm := t.loadRealm()\n\t\t\trequire.Len(t, realm.Schemas, 1)\n\t\t\tts, ok := realm.Schemas[0].Table(n)\n\t\t\trequire.True(t, ok)\n\t\t\texpected := schema.Table{\n\t\t\t\tName: n,\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t&schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t\t&mysql.Engine{V: \"InnoDB\", Default: true},\n\t\t\t\t},\n\t\t\t\tSchema: realm.Schemas[0],\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:    \"tBit\",\n\t\t\t\t\t\tType:    &schema.ColumnType{Type: &mysql.BitType{T: \"bit\", Size: 10}, Raw: \"bit(10) unsigned\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"b'1000000001'\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tInt\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"int\"}, \"int(10)\"), Null: false},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTinyInt\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"tinyint\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"tinyint\"}, \"tinyint(10)\"), Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"8\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tSmallInt\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"smallint\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"smallint\"}, \"smallint(10)\"), Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"2\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tMediumInt\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"mediumint\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"mediumint\"}, \"mediumint(10)\"), Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"11\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tBigInt\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"bigint\"}, \"bigint(10)\"), Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tDecimal\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\", Precision: 10},\n\t\t\t\t\t\t\tRaw: \"decimal(10,0)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tNumeric\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\", Precision: 10},\n\t\t\t\t\t\t\tRaw: \"decimal(10,0)\", Null: false},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tFloat\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.FloatType{T: \"float\"},\n\t\t\t\t\t\t\tRaw: \"float\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tDouble\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.FloatType{T: \"double\"},\n\t\t\t\t\t\t\tRaw: \"double\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tReal\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.FloatType{T: \"double\"},\n\t\t\t\t\t\t\tRaw: \"double\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTimestamp\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp\"},\n\t\t\t\t\t\t\tRaw: \"timestamp\", Null: true},\n\t\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\t\tX: \"CURRENT_TIMESTAMP\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTimestampFraction\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp\", Precision: intp(6)},\n\t\t\t\t\t\t\tRaw: \"timestamp(6)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\t\tX: \"CURRENT_TIMESTAMP(6)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTimestampOnUpdate\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp\"},\n\t\t\t\t\t\t\tRaw: \"timestamp\", Null: true},\n\t\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\t\tX: \"CURRENT_TIMESTAMP\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&mysql.OnUpdate{\n\t\t\t\t\t\t\t\tA: \"CURRENT_TIMESTAMP\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTimestampFractionOnUpdate\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"timestamp\", Precision: intp(6)},\n\t\t\t\t\t\t\tRaw: \"timestamp(6)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.RawExpr{\n\t\t\t\t\t\t\tX: \"CURRENT_TIMESTAMP(6)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&mysql.OnUpdate{\n\t\t\t\t\t\t\t\tA: \"CURRENT_TIMESTAMP(6)\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tDate\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"date\"},\n\t\t\t\t\t\t\tRaw: \"date\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTime\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"time\"},\n\t\t\t\t\t\t\tRaw: \"time\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tDateTime\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"datetime\"},\n\t\t\t\t\t\t\tRaw: \"datetime\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tYear\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.TimeType{T: \"year\", Precision: intp(t.intByVersion(map[string]int{\"mysql8\": 0}, 4))},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"year\"}, \"year(4) unsigned\"), Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tVarchar\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"varchar\", Size: 10},\n\t\t\t\t\t\t\tRaw: \"varchar(10)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: t.quoted(\"Titan\")},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tChar\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"char\", Size: 25},\n\t\t\t\t\t\t\tRaw: \"char(25)\", Null: false},\n\t\t\t\t\t\tDefault: &schema.Literal{V: t.quoted(\"Olimpia\")},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tVarBinary\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"varbinary\", Size: intp(30)},\n\t\t\t\t\t\t\tRaw: \"varbinary(30)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: t.valueByVersion(map[string]string{\"mysql8\": \"0x546974616E\"}, t.quoted(\"Titan\"))},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tBinary\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"binary\", Size: intp(5)},\n\t\t\t\t\t\t\tRaw: \"binary(5)\", Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: t.valueByVersion(map[string]string{\"mysql8\": \"0x546974616E\"}, t.quoted(\"Titan\"))},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tBlob\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"tinyblob\"},\n\t\t\t\t\t\t\tRaw: \"tinyblob\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTinyBlob\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"tinyblob\"},\n\t\t\t\t\t\t\tRaw: \"tinyblob\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tMediumBlob\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"mediumblob\"},\n\t\t\t\t\t\t\tRaw: \"mediumblob\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tLongBlob\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.BinaryType{T: \"longblob\"},\n\t\t\t\t\t\t\tRaw: \"longblob\", Null: true},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tText\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"tinytext\"},\n\t\t\t\t\t\t\tRaw: \"tinytext\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tTinyText\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"tinytext\"},\n\t\t\t\t\t\t\tRaw: \"tinytext\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tMediumText\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"mediumtext\", Size: 0},\n\t\t\t\t\t\t\tRaw: \"mediumtext\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tLongText\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"longtext\", Size: 0},\n\t\t\t\t\t\t\tRaw: \"longtext\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tEnum\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.EnumType{T: \"enum\", Values: []string{\"a\", \"b\"}},\n\t\t\t\t\t\t\tRaw: \"enum('a','b')\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tSet\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &mysql.SetType{Values: []string{\"a\", \"b\"}},\n\t\t\t\t\t\t\tRaw: \"set('a','b')\", Null: true},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\trmCreateStmt(ts)\n\t\t\trequire.EqualValues(t, &expected, ts)\n\t\t\tt.hclDriftTest(n, realm, expected)\n\t\t})\n\t})\n\tt.Run(\"JSON\", func(t *testing.T) {\n\t\tddl := `\n\tcreate table atlas_types_sanity\n\t(\n\t    tJSON         json          default                   null\n\t) CHARSET = latin1;\n\t`\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tt.dropTables(n)\n\t\t\t_, err := t.db.Exec(ddl)\n\t\t\trequire.NoError(t, err)\n\t\t\trealm := t.loadRealm()\n\t\t\trequire.Len(t, realm.Schemas, 1)\n\t\t\tts, ok := realm.Schemas[0].Table(n)\n\t\t\trequire.True(t, ok)\n\t\t\texpected := schema.Table{\n\t\t\t\tName: n,\n\t\t\t\tAttrs: func() []schema.Attr {\n\t\t\t\t\treturn []schema.Attr{\n\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t&schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t\t\t&mysql.Engine{V: \"InnoDB\", Default: true},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t\tSchema: realm.Schemas[0],\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"tJSON\", Type: &schema.ColumnType{Type: &schema.JSONType{T: \"json\"}, Raw: \"json\", Null: true}},\n\t\t\t\t},\n\t\t\t}\n\t\t\trmCreateStmt(ts)\n\t\t\trequire.EqualValues(t, &expected, ts)\n\t\t})\n\t})\n\n\tt.Run(\"ImplicitIndexes\", func(t *testing.T) {\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\ttestImplicitIndexes(t, t.db)\n\t\t})\n\t})\n\n\tt.Run(\"AltersOrder\", func(t *testing.T) {\n\t\tddl := `\n\t\tcreate table tidb_alter_order(\n\t\t\ttBigInt bigint(10) default 4 null,\n\t\t\tINDEX   i  (tBigInt)\n\t\t);\n\t`\n\t\ttidbRun(t, func(t *myTest) {\n\t\t\tt.dropTables(\"tidb_alter_order\")\n\t\t\t_, err := t.db.Exec(ddl)\n\t\t\trequire.NoError(t, err)\n\t\t\ttbl := t.loadTable(\"tidb_alter_order\")\n\t\t\trequire.NotNil(t, tbl)\n\t\t\tto := schema.Table{\n\t\t\t\tName: \"tidb_alter_order\",\n\t\t\t\tAttrs: func() []schema.Attr {\n\t\t\t\t\treturn []schema.Attr{\n\t\t\t\t\t\t&schema.Collation{V: \"utf8mb4_bin\"},\n\t\t\t\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t\t\t&mysql.Engine{V: \"InnoDB\", Default: true},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"tBigInt2\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\", Unsigned: false},\n\t\t\t\t\t\t\tRaw: t.valueByVersion(map[string]string{\"mysql8\": \"bigint\"}, \"bigint(10)\"), Null: true},\n\t\t\t\t\t\tDefault: &schema.Literal{V: \"4\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\tto.AddIndexes(\n\t\t\t\t&schema.Index{Name: \"i2\", Parts: []*schema.IndexPart{\n\t\t\t\t\t{\n\t\t\t\t\t\tC:    to.Columns[0],\n\t\t\t\t\t\tDesc: true,\n\t\t\t\t\t},\n\t\t\t\t}})\n\t\t\tchanges, err := t.drv.SchemaDiff(schema.New(\"test\").AddTables(tbl), schema.New(\"test\").AddTables(&to))\n\t\t\trequire.NoError(t, err)\n\t\t\terr = t.drv.ApplyChanges(context.Background(), changes)\n\t\t\trequire.NoError(t, err)\n\t\t\tt.migrate()\n\t\t\trmCreateStmt(tbl)\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "internal/integration/tools.go",
    "content": "//go:build tools\n// +build tools\n\npackage main\n\nimport (\n\t_ \"ariga.io/atlas/cmd/atlas\"\n)\n"
  },
  {
    "path": "schemahcl/context.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/hashicorp/hcl/v2/gohcl\"\n\t\"github.com/hashicorp/hcl/v2/hclsyntax\"\n\t\"github.com/zclconf/go-cty/cty\"\n\t\"github.com/zclconf/go-cty/cty/convert\"\n)\n\n// blockVar is an HCL resource that defines an input variable to the Atlas DDL document.\ntype blockVar struct {\n\tName        string    `hcl:\",label\"`\n\tType        cty.Value `hcl:\"type\"`\n\tDefault     cty.Value `hcl:\"default,optional\"`\n\tDescription string    `hcl:\"description,optional\"`\n}\n\n// setInputVals sets the input values into the evaluation context. HCL documents can define\n// input variables in the document body by defining \"variable\" blocks:\n//\n//\tvariable \"name\" {\n//\t  type = string // also supported: number, bool\n//\t  default = \"rotemtam\"\n//\t}\nfunc (s *State) setInputVals(ctx *hcl.EvalContext, body hcl.Body, input map[string]cty.Value) error {\n\tvar doc struct {\n\t\tVars   []*blockVar `hcl:\"variable,block\"`\n\t\tRemain hcl.Body    `hcl:\",remain\"`\n\t}\n\tif diag := gohcl.DecodeBody(body, ctx, &doc); diag.HasErrors() {\n\t\treturn diag\n\t}\n\tctxVars := make(map[string]cty.Value)\n\tfor _, v := range doc.Vars {\n\t\tvar vv cty.Value\n\t\tswitch iv, ok := input[v.Name]; {\n\t\tcase !v.Type.Type().IsCapsuleType():\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"invalid type %q for variable %q. Valid types are: string, number, bool, list, map, or set\",\n\t\t\t\tv.Type.AsString(), v.Name,\n\t\t\t)\n\t\tcase ok:\n\t\t\tvv = iv\n\t\tcase v.Default != cty.NilVal:\n\t\t\tvv = v.Default\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"missing value for required variable %q\", v.Name)\n\t\t}\n\t\tvt := v.Type.EncapsulatedValue().(*cty.Type)\n\t\t// In case the input value is a primitive type and the expected type is a list,\n\t\t// wrap it as a list because the variable type may not be known to the caller.\n\t\tif vt.IsListType() && vv.Type().Equals(vt.ElementType()) {\n\t\t\tvv = cty.ListVal([]cty.Value{vv})\n\t\t}\n\t\tcv, err := convert.Convert(vv, *vt)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"variable %q: %w\", v.Name, err)\n\t\t}\n\t\tctxVars[v.Name] = cv\n\t}\n\tmergeCtxVar(ctx, ctxVars)\n\treturn nil\n}\n\n// evalReferences evaluates local and data blocks.\nfunc (s *State) evalReferences(ctx *hcl.EvalContext, body *hclsyntax.Body) error {\n\ttype node struct {\n\t\taddr  [3]string\n\t\tedges func() []hcl.Traversal\n\t\tvalue func() (cty.Value, error)\n\t}\n\tvar (\n\t\tinitblk []*node\n\t\tgoctx   = s.config.ctx\n\t\ttypeblk = make(map[string]bool)\n\t\tnodes   = make(map[[3]string]*node)\n\t\tblocks  = make(hclsyntax.Blocks, 0, len(body.Blocks))\n\t)\n\tif goctx == nil {\n\t\tgoctx = context.Background()\n\t}\n\tfor _, b := range body.Blocks {\n\t\tswitch b := b; {\n\t\tcase b.Type == BlockData:\n\t\t\tif len(b.Labels) < 2 {\n\t\t\t\treturn fmt.Errorf(\"data block %q must have exactly 2 labels\", b.Type)\n\t\t\t}\n\t\t\th, ok := s.config.datasrc[b.Labels[0]]\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"missing data source handler for %q\", b.Labels[0])\n\t\t\t}\n\t\t\t// Data references are combined from\n\t\t\t// \"data\", \"source\" and \"name\" labels.\n\t\t\taddr := [3]string{RefData, b.Labels[0], b.Labels[1]}\n\t\t\tnodes[addr] = &node{\n\t\t\t\taddr:  addr,\n\t\t\t\tvalue: func() (cty.Value, error) { return h(goctx, ctx, b) },\n\t\t\t\tedges: func() []hcl.Traversal { return bodyVars(b.Body) },\n\t\t\t}\n\t\tcase b.Type == BlockLocals:\n\t\t\tfor k, v := range b.Body.Attributes {\n\t\t\t\tk, v := k, v\n\t\t\t\t// Local references are combined from\n\t\t\t\t// \"local\" and \"name\" labels.\n\t\t\t\taddr := [3]string{RefLocal, k, \"\"}\n\t\t\t\tnodes[addr] = &node{\n\t\t\t\t\taddr:  addr,\n\t\t\t\t\tedges: func() []hcl.Traversal { return hclsyntax.Variables(v.Expr) },\n\t\t\t\t\tvalue: func() (cty.Value, error) {\n\t\t\t\t\t\tv, diags := v.Expr.Value(ctx)\n\t\t\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn v, nil\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t}\n\t\tcase s.config.initblk[b.Type] != nil:\n\t\t\tif len(b.Labels) != 0 {\n\t\t\t\treturn fmt.Errorf(\"init block %q cannot have labels\", b.Type)\n\t\t\t}\n\t\t\taddr := [3]string{b.Type, \"\", \"\"}\n\t\t\tif nodes[addr] != nil {\n\t\t\t\treturn fmt.Errorf(\"duplicate init block %q\", b.Type)\n\t\t\t}\n\t\t\th := s.config.initblk[b.Type]\n\t\t\tn := &node{\n\t\t\t\taddr:  addr,\n\t\t\t\tvalue: func() (cty.Value, error) { return h(goctx, ctx, b) },\n\t\t\t\tedges: func() []hcl.Traversal { return bodyVars(b.Body) },\n\t\t\t}\n\t\t\tnodes[addr] = n\n\t\t\tinitblk = append(initblk, n)\n\t\tcase s.config.typedblk[b.Type] != nil:\n\t\t\ttypeblk[b.Type] = true\n\t\t\tif len(b.Labels) < 2 {\n\t\t\t\treturn fmt.Errorf(\"%s block must have exactly 2 labels\", b.Type)\n\t\t\t}\n\t\t\tk, ok := s.config.typedblk[b.Type]\n\t\t\tif !ok || k[b.Labels[0]] == nil {\n\t\t\t\treturn fmt.Errorf(\"missing %s block handler for %q\", b.Type, b.Labels[0])\n\t\t\t}\n\t\t\th := k[b.Labels[0]]\n\t\t\t// Typed block references are combined from\n\t\t\t// \"<type>\", \"<label>\" and \"name\" labels.\n\t\t\taddr := [3]string{b.Type, b.Labels[0], b.Labels[1]}\n\t\t\tnodes[addr] = &node{\n\t\t\t\taddr:  addr,\n\t\t\t\tvalue: func() (cty.Value, error) { return h(goctx, ctx, b) },\n\t\t\t\tedges: func() []hcl.Traversal { return bodyVars(b.Body) },\n\t\t\t}\n\t\tdefault:\n\t\t\tblocks = append(blocks, b)\n\t\t}\n\t}\n\tvar (\n\t\tvisit    func(*node) error\n\t\tvisited  = make(map[*node]bool)\n\t\tprogress = make(map[*node]bool)\n\t)\n\tvisit = func(n *node) error {\n\t\tif visited[n] {\n\t\t\treturn nil\n\t\t}\n\t\tif progress[n] {\n\t\t\taddr := n.addr[:]\n\t\t\tfor len(addr) > 0 && addr[len(addr)-1] == \"\" {\n\t\t\t\taddr = addr[:len(addr)-1]\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"cyclic reference to %q\", strings.Join(addr, \".\"))\n\t\t}\n\t\tprogress[n] = true\n\t\tfor _, e := range n.edges() {\n\t\t\tvar addr [3]string\n\t\t\tswitch root := e.RootName(); {\n\t\t\tcase root == RefLocal && len(e) > 1:\n\t\t\t\taddr = [3]string{RefLocal, e[1].(hcl.TraverseAttr).Name, \"\"}\n\t\t\tcase (root == RefData || typeblk[e.RootName()]) && len(e) > 2:\n\t\t\t\taddr = [3]string{e.RootName(), e[1].(hcl.TraverseAttr).Name, e[2].(hcl.TraverseAttr).Name}\n\t\t\tcase s.config.initblk[root] != nil && len(e) == 1:\n\t\t\t\taddr = [3]string{root, \"\", \"\"}\n\t\t\t}\n\t\t\t// Unrecognized reference.\n\t\t\tif nodes[addr] == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif err := visit(nodes[addr]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tdelete(progress, n)\n\t\tv, err := n.value()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch {\n\t\tcase n.addr[0] == RefData, typeblk[n.addr[0]]:\n\t\t\ttop := make(map[string]cty.Value)\n\t\t\tif vv, ok := ctx.Variables[n.addr[0]]; ok {\n\t\t\t\ttop = vv.AsValueMap()\n\t\t\t}\n\t\t\ttyp := make(map[string]cty.Value)\n\t\t\tif vv, ok := top[n.addr[1]]; ok {\n\t\t\t\ttyp = vv.AsValueMap()\n\t\t\t}\n\t\t\ttyp[n.addr[2]] = v\n\t\t\ttop[n.addr[1]] = cty.ObjectVal(typ)\n\t\t\tctx.Variables[n.addr[0]] = cty.ObjectVal(top)\n\t\tcase n.addr[0] == RefLocal:\n\t\t\tlocals := make(map[string]cty.Value)\n\t\t\tif vv, ok := ctx.Variables[RefLocal]; ok {\n\t\t\t\tlocals = vv.AsValueMap()\n\t\t\t}\n\t\t\tlocals[n.addr[1]] = v\n\t\t\tctx.Variables[RefLocal] = cty.ObjectVal(locals)\n\t\tdefault:\n\t\t\tctx.Variables[n.addr[0]] = v\n\t\t}\n\t\treturn nil\n\t}\n\t// Evaluate init-blocks first,\n\t// to give them higher precedence.\n\tfor _, n := range initblk {\n\t\tif err := visit(n); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\t// New body without locals, data-sources, typed-blocks attached.\n\tbody.Blocks = blocks\n\ttyperef := map[string][]hcl.Traversal{\n\t\tRefData: typeRefs(RefData, body),\n\t}\n\tfor n := range typeblk {\n\t\ttyperef[n] = typeRefs(n, body)\n\t}\n\tfor _, n := range nodes {\n\t\t// Evaluate type-blocks and data sources only if they were referenced by\n\t\t// other top-level blocks/attributes or if they reference other evaluated\n\t\t// data sources.\n\t\tif refs, ok := typeref[n.addr[0]]; ok {\n\t\t\texists := func() bool {\n\t\t\t\tfor _, r := range refs {\n\t\t\t\t\tt, ok1 := r[1].(hcl.TraverseAttr)\n\t\t\t\t\tl, ok2 := r[2].(hcl.TraverseAttr)\n\t\t\t\t\tif ok1 && ok2 && t.Name == n.addr[1] && l.Name == n.addr[2] {\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t}()\n\t\t\tif !exists {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tif err := visit(n); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc mergeCtxVar(ctx *hcl.EvalContext, values map[string]cty.Value) {\n\tv, ok := ctx.Variables[RefVar]\n\tif ok {\n\t\tv.ForEachElement(func(key cty.Value, val cty.Value) (stop bool) {\n\t\t\tvalues[key.AsString()] = val\n\t\t\treturn false\n\t\t})\n\t}\n\tctx.Variables[RefVar] = cty.ObjectVal(values)\n}\n\nfunc blockVars(blocks hclsyntax.Blocks, parentAddr string, defs *blockDef) (map[string]cty.Value, error) {\n\tvars := make(map[string]cty.Value)\n\tfor name, def := range defs.children {\n\t\tblocks := blocksOfType(blocks, name)\n\t\tif len(blocks) == 0 {\n\t\t\tvars[name] = cty.NullVal(def.asCty())\n\t\t\tcontinue\n\t\t}\n\t\tvar (\n\t\t\tunlabeled int\n\t\t\tv         = make(map[string]cty.Value)\n\t\t\tqv        = make(map[string]map[string]cty.Value)\n\t\t)\n\t\tfor _, blk := range blocks {\n\t\t\tqualifier, blkName := blockName(blk)\n\t\t\tif blkName == \"\" {\n\t\t\t\tblkName = strconv.Itoa(unlabeled)\n\t\t\t\tunlabeled++\n\t\t\t}\n\t\t\tattrs := attrMap(blk.Body.Attributes)\n\t\t\tself := addr(parentAddr, name, blkName, qualifier)\n\t\t\tattrs[\"__ref\"] = cty.StringVal(self)\n\t\t\t// Skip naming blocks with \"name\" attribute.\n\t\t\tif _, ok := blk.Body.Attributes[\"name\"]; !ok {\n\t\t\t\tattrs[\"name\"] = cty.StringVal(blkName)\n\t\t\t}\n\t\t\tvarMap, err := blockVars(blk.Body.Blocks, self, def)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\t// Merge children blocks in.\n\t\t\tfor k, v := range varMap {\n\t\t\t\tattrs[k] = v\n\t\t\t}\n\t\t\tswitch {\n\t\t\tcase qualifier != \"\":\n\t\t\t\tobj := cty.ObjectVal(attrs)\n\t\t\t\tif _, ok := qv[qualifier]; !ok {\n\t\t\t\t\tqv[qualifier] = make(map[string]cty.Value)\n\t\t\t\t}\n\t\t\t\tqv[qualifier][blkName] = obj\n\t\t\t\tobj = cty.ObjectVal(qv[qualifier])\n\t\t\t\tv[qualifier] = obj\n\t\t\tdefault:\n\t\t\t\tv[blkName] = cty.ObjectVal(attrs)\n\t\t\t}\n\t\t}\n\t\tif len(v) > 0 {\n\t\t\tvars[name] = cty.ObjectVal(v)\n\t\t}\n\t}\n\treturn vars, nil\n}\n\nfunc addr(parentAddr, typeName, blkName, qualifier string) string {\n\tvar b strings.Builder\n\tif parentAddr != \"\" {\n\t\tb.WriteString(parentAddr)\n\t\tb.WriteString(\".\")\n\t}\n\tb.WriteByte('$')\n\tb.WriteString(typeName)\n\tfor _, s := range []string{qualifier, blkName} {\n\t\tswitch {\n\t\tcase s == \"\":\n\t\tcase validIdent(s):\n\t\t\tb.WriteString(\".\")\n\t\t\tb.WriteString(s)\n\t\tdefault:\n\t\t\tb.WriteString(\"[\")\n\t\t\tb.WriteString(strconv.Quote(s))\n\t\t\tb.WriteString(\"]\")\n\t\t}\n\t}\n\treturn b.String()\n}\n\n// validIdent reports if the given string can\n// be used as an identifier in a reference.\nfunc validIdent(s string) bool {\n\t_, err := cty.ParseNumberVal(s)\n\treturn err == nil || hclsyntax.ValidIdentifier(s)\n}\n\nfunc blockName(blk *hclsyntax.Block) (qualifier string, name string) {\n\tswitch len(blk.Labels) {\n\tcase 0:\n\tcase 1:\n\t\tname = blk.Labels[0]\n\tdefault:\n\t\tqualifier = blk.Labels[0]\n\t\tname = blk.Labels[1]\n\t}\n\treturn\n}\n\nfunc blocksOfType(blocks hclsyntax.Blocks, typeName string) []*hclsyntax.Block {\n\tvar out []*hclsyntax.Block\n\tfor _, block := range blocks {\n\t\tif block.Type == typeName {\n\t\t\tout = append(out, block)\n\t\t}\n\t}\n\treturn out\n}\n\nfunc attrMap(attrs hclsyntax.Attributes) map[string]cty.Value {\n\tout := make(map[string]cty.Value, len(attrs))\n\tfor _, v := range attrs {\n\t\tif value, diag := v.Expr.Value(nil); !diag.HasErrors() {\n\t\t\tout[v.Name] = value\n\t\t}\n\t}\n\treturn out\n}\n\nvar (\n\tctyNilType  = cty.Capsule(\"type\", reflect.TypeOf(cty.NilType))\n\tctyTypeSpec = cty.Capsule(\"type\", reflect.TypeOf(Type{}))\n\tctyRefType  = cty.Capsule(\"ref\", reflect.TypeOf(Ref{}))\n\tctyRawExpr  = cty.Capsule(\"raw\", reflect.TypeOf(RawExpr{}))\n)\n\n// Built-in blocks.\nconst (\n\tBlockData     = \"data\"\n\tBlockLocals   = \"locals\"\n\tBlockVariable = \"variable\"\n\tRefData       = \"data\"\n\tRefVar        = \"var\"\n\tRefLocal      = \"local\"\n\tAttrName      = \"name\"\n\tforEachAttr   = \"for_each\"\n\teachRef       = \"each\"\n)\n\n// Variables represents the dynamic variables used in a body.\ntype Variables struct {\n\tVar, Local map[string]bool\n\tData       map[string]map[string]bool\n}\n\n// blockDef describes a type of block in the HCL document.\ntype blockDef struct {\n\tname     string\n\tparent   *blockDef\n\tchildren map[string]*blockDef\n\t// Cached cty.Type.\n\tcty *cty.Type\n}\n\nfunc (t *blockDef) child(typ string) *blockDef {\n\tif t.children[typ] == nil {\n\t\treturn &blockDef{}\n\t}\n\treturn t.children[typ]\n}\n\nfunc (t *blockDef) addChild(blk *hclsyntax.Block, depth int) {\n\tif t.children == nil {\n\t\tt.children = make(map[string]*blockDef)\n\t}\n\tc, ok := t.children[blk.Type]\n\tif !ok {\n\t\tc = &blockDef{\n\t\t\tname:   blk.Type,\n\t\t\tparent: t,\n\t\t}\n\t\tt.children[blk.Type] = c\n\t}\n\t// Limit depth of children to two as we do not have any\n\t// case for more than this atm. e.g., table.column.\n\tif depth < 2 {\n\t\tfor _, bc := range blk.Body.Blocks {\n\t\t\tc.addChild(bc, depth+1)\n\t\t}\n\t}\n}\n\n// asCty returns a cty.Type representing the blockDef.\nfunc (t *blockDef) asCty() cty.Type {\n\tif t.cty != nil {\n\t\treturn *t.cty\n\t}\n\tf := make(map[string]cty.Type)\n\tf[\"name\"] = cty.String\n\tf[\"__ref\"] = cty.String\n\tfor _, c := range t.children {\n\t\tf[c.name] = c.asCty()\n\t}\n\tv := cty.Object(f)\n\tt.cty = &v\n\treturn v\n}\n\nfunc bodyVars(b *hclsyntax.Body) (vars []hcl.Traversal) {\n\tfor _, a := range b.Attributes {\n\t\tvars = append(vars, hclsyntax.Variables(a.Expr)...)\n\t}\n\tfor _, b := range b.Blocks {\n\t\tvars = append(vars, bodyVars(b.Body)...)\n\t}\n\treturn\n}\n\n// typeRefs returns all type referenced in the body.\nfunc typeRefs(name string, b *hclsyntax.Body) (refs []hcl.Traversal) {\n\tfor _, a := range b.Attributes {\n\t\tfor _, v := range hclsyntax.Variables(a.Expr) {\n\t\t\tif v.RootName() == name {\n\t\t\t\trefs = append(refs, v)\n\t\t\t}\n\t\t}\n\t}\n\tfor _, b := range b.Blocks {\n\t\tif b.Type != name {\n\t\t\trefs = append(refs, typeRefs(name, b.Body)...)\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "schemahcl/context_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\nfunc TestReferences(t *testing.T) {\n\tf := `\nbackend \"app\" {\n\timage = \"ariga/app:1.2.3\"\n\taddr = \"127.0.0.1:8081\"\n}\nbackend \"admin\" {\n\timage = \"ariga/admin:1.2.3\"\n\taddr = \"127.0.0.1:8082\"\n}\nendpoint \"home\" {\n\tpath = \"/\"\n\taddr = backend.app.addr\n\ttimeout_ms = config.defaults.timeout_ms\n\tretry = config.defaults.retry\n\tdescription = \"default: ${config.defaults.description}\"\n}\nendpoint \"admin\" {\n\tpath = \"/admin\"\n\taddr = backend.admin.addr\n}\nconfig \"defaults\" {\n\ttimeout_ms = 10\n\tretry = false\n\tdescription = \"generic\"\n}\n`\n\ttype (\n\t\tBackend struct {\n\t\t\tName  string `spec:\",name\"`\n\t\t\tImage string `spec:\"image\"`\n\t\t\tAddr  string `spec:\"addr\"`\n\t\t}\n\t\tEndpoint struct {\n\t\t\tName      string `spec:\",name\"`\n\t\t\tPath      string `spec:\"path\"`\n\t\t\tAddr      string `spec:\"addr\"`\n\t\t\tTimeoutMs int    `spec:\"timeout_ms\"`\n\t\t\tRetry     bool   `spec:\"retry\"`\n\t\t\tDesc      string `spec:\"description\"`\n\t\t}\n\t)\n\tvar test struct {\n\t\tBackends  []*Backend  `spec:\"backend\"`\n\t\tEndpoints []*Endpoint `spec:\"endpoint\"`\n\t}\n\terr := New().EvalBytes([]byte(f), &test, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, []*Endpoint{\n\t\t{\n\t\t\tName:      \"home\",\n\t\t\tPath:      \"/\",\n\t\t\tAddr:      \"127.0.0.1:8081\",\n\t\t\tRetry:     false,\n\t\t\tTimeoutMs: 10,\n\t\t\tDesc:      \"default: generic\",\n\t\t},\n\t\t{\n\t\t\tName: \"admin\",\n\t\t\tPath: \"/admin\",\n\t\t\tAddr: \"127.0.0.1:8082\",\n\t\t},\n\t}, test.Endpoints)\n}\n\nfunc TestUnlabeledBlockReferences(t *testing.T) {\n\tf := `\ncountry \"israel\" {\n    metadata {\n        phone_prefix = \"972\"\n    }\n    metadata {\n        phone_prefix = \"123\"\n    }\n    metadata \"geo\" {\n\t\tcontinent = \"asia\"\n    }\n}\n\nmetadata  = country.israel.metadata.0\nphone_prefix = country.israel.metadata.0.phone_prefix\nphone_prefix_2 = country.israel.metadata.1.phone_prefix\ncontinent = country.israel.metadata.geo.continent\n`\n\ttype (\n\t\tMetadata struct {\n\t\t\tPhonePrefix string `spec:\"phone_prefix\"`\n\t\t\tContinent   string `spec:\"continent\"`\n\t\t}\n\t\tCountry struct {\n\t\t\tMetadata []*Metadata `spec:\"metadata\"`\n\t\t}\n\t\tTest struct {\n\t\t\tCountries    []*Country `spec:\"country\"`\n\t\t\tMetadataRef  *Ref       `spec:\"metadata\"`\n\t\t\tPhonePrefix  string     `spec:\"phone_prefix\"`\n\t\t\tPhonePrefix2 string     `spec:\"phone_prefix_2\"`\n\t\t\tContinent    string     `spec:\"continent\"`\n\t\t}\n\t)\n\tvar test Test\n\terr := New().EvalBytes([]byte(f), &test, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, test, Test{\n\t\tCountries: []*Country{\n\t\t\t{\n\t\t\t\tMetadata: []*Metadata{\n\t\t\t\t\t{PhonePrefix: \"972\"},\n\t\t\t\t\t{PhonePrefix: \"123\"},\n\t\t\t\t\t{Continent: \"asia\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tMetadataRef:  &Ref{V: \"$country.israel.$metadata.0\"},\n\t\tPhonePrefix:  \"972\",\n\t\tPhonePrefix2: \"123\",\n\t\tContinent:    \"asia\",\n\t})\n}\n\nfunc TestNestedReferences(t *testing.T) {\n\tf := `\ncountry \"israel\" {\n\tcity \"tel_aviv\" {\n\t\tphone_area_code = \"03\"\n\t}\n\tcity \"jerusalem\" {\n\t\tphone_area_code = \"02\"\n\t}\n\tcity \"givatayim\" {\n\t\tphone_area_code = country.israel.city.tel_aviv.phone_area_code\n\t}\n}\n`\n\ttype (\n\t\tCity struct {\n\t\t\tName          string `spec:\",name\"`\n\t\t\tPhoneAreaCode string `spec:\"phone_area_code\"`\n\t\t}\n\t\tCountry struct {\n\t\t\tName   string  `spec:\",name\"`\n\t\t\tCities []*City `spec:\"city\"`\n\t\t}\n\t)\n\tvar test struct {\n\t\tCountries []*Country `spec:\"country\"`\n\t}\n\terr := New().EvalBytes([]byte(f), &test, nil)\n\tisrael := &Country{\n\t\tName: \"israel\",\n\t\tCities: []*City{\n\t\t\t{Name: \"tel_aviv\", PhoneAreaCode: \"03\"},\n\t\t\t{Name: \"jerusalem\", PhoneAreaCode: \"02\"},\n\t\t\t{Name: \"givatayim\", PhoneAreaCode: \"03\"},\n\t\t},\n\t}\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, israel, test.Countries[0])\n}\n\nfunc TestBlockReference(t *testing.T) {\n\tf := `person \"jon\" {\n}\npet \"garfield\" {\n  type  = \"cat\"\n  owner = person.jon\n}\n`\n\ttype (\n\t\tPerson struct {\n\t\t\tName string `spec:\",name\"`\n\t\t}\n\t\tPet struct {\n\t\t\tName  string `spec:\",name\"`\n\t\t\tType  string `spec:\"type\"`\n\t\t\tOwner *Ref   `spec:\"owner\"`\n\t\t}\n\t)\n\tvar test struct {\n\t\tPeople []*Person `spec:\"person\"`\n\t\tPets   []*Pet    `spec:\"pet\"`\n\t}\n\terr := New().EvalBytes([]byte(f), &test, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, &Pet{\n\t\tName:  \"garfield\",\n\t\tType:  \"cat\",\n\t\tOwner: &Ref{V: \"$person.jon\"},\n\t}, test.Pets[0])\n\tmarshal, err := Marshal(&test)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, f, string(marshal))\n}\n\nfunc TestListRefs(t *testing.T) {\n\tf := `\nuser \"simba\" {\n\t\n}\nuser \"mufasa\" {\n\n}\ngroup \"lion_kings\" {\n\tmembers = [\n\t\tuser.simba,\n\t\tuser.mufasa,\n\t]\n}\n`\n\ttype (\n\t\tUser struct {\n\t\t\tName string `spec:\",name\"`\n\t\t}\n\t\tGroup struct {\n\t\t\tName    string `spec:\",name\"`\n\t\t\tMembers []*Ref `spec:\"members\"`\n\t\t}\n\t)\n\tvar test struct {\n\t\tUsers  []*User  `spec:\"user\"`\n\t\tGroups []*Group `spec:\"group\"`\n\t}\n\terr := New().EvalBytes([]byte(f), &test, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, &Group{\n\t\tName: \"lion_kings\",\n\t\tMembers: []*Ref{\n\t\t\t{V: \"$user.simba\"},\n\t\t\t{V: \"$user.mufasa\"},\n\t\t},\n\t}, test.Groups[0])\n\t_, err = Marshal(&test)\n\trequire.NoError(t, err)\n}\n\nfunc TestNestedDifference(t *testing.T) {\n\tf := `\nperson \"john\" {\n\tnickname = \"jonnie\"\n\thobby \"hockey\" {\n\t\tactive = true\n\t}\n}\nperson \"jane\" {\n\tnickname = \"janie\"\n\thobby \"football\" {\n\t\tbudget = 1000\n\t}\n\tcar \"ferrari\" {\n\t\tyear = 1960\n\t}\n}\n`\n\ttype (\n\t\tHobby struct {\n\t\t\tName   string `spec:\",name\"`\n\t\t\tActive bool   `spec:\"active\"`\n\t\t\tBudget int    `spec:\"budget\"`\n\t\t}\n\t\tCar struct {\n\t\t\tName string `spec:\",name\"`\n\t\t\tYear int    `spec:\"year\"`\n\t\t}\n\t\tPerson struct {\n\t\t\tName     string   `spec:\",name\"`\n\t\t\tNickname string   `spec:\"nickname\"`\n\t\t\tHobbies  []*Hobby `spec:\"hobby\"`\n\t\t\tCar      *Car     `spec:\"car\"`\n\t\t}\n\t)\n\tvar test struct {\n\t\tPeople []*Person `spec:\"person\"`\n\t}\n\terr := New().EvalBytes([]byte(f), &test, nil)\n\trequire.NoError(t, err)\n\tjohn := &Person{\n\t\tName:     \"john\",\n\t\tNickname: \"jonnie\",\n\t\tHobbies: []*Hobby{\n\t\t\t{Name: \"hockey\", Active: true},\n\t\t},\n\t}\n\trequire.EqualValues(t, john, test.People[0])\n\tjane := &Person{\n\t\tName:     \"jane\",\n\t\tNickname: \"janie\",\n\t\tHobbies: []*Hobby{\n\t\t\t{Name: \"football\", Budget: 1000},\n\t\t},\n\t\tCar: &Car{\n\t\t\tName: \"ferrari\",\n\t\t\tYear: 1960,\n\t\t},\n\t}\n\trequire.EqualValues(t, jane, test.People[1])\n}\n\nfunc TestSchemaRefParse(t *testing.T) {\n\ttype Point struct {\n\t\tZ []*Ref `spec:\"z\"`\n\t}\n\tvar test = struct {\n\t\tPoints []*Point `spec:\"point\"`\n\t}{\n\t\tPoints: []*Point{\n\t\t\t{Z: []*Ref{{V: \"$point.1\"}}},\n\t\t\t{Z: []*Ref{{V: \"$point.0\"}}},\n\t\t},\n\t}\n\tb, err := Marshal(&test)\n\trequire.NoError(t, err)\n\texpected :=\n\t\t`point {\n  z = [point.1]\n}\npoint {\n  z = [point.0]\n}\n`\n\trequire.Equal(t, expected, string(b))\n}\n\nfunc TestWithTypes(t *testing.T) {\n\tf := `parent \"name\" {\n  child \"name\" {\n    first    = int\n    second   = bool\n    third    = int(10)\n    sized    = varchar(255)\n    variadic = enum(\"a\",\"b\",\"c\")\n  }\n}\n`\n\ts := New(\n\t\tWithTypes(\n\t\t\t\"parent.child\",\n\t\t\t[]*TypeSpec{\n\t\t\t\t{Name: \"bool\", T: \"bool\"},\n\t\t\t\t{\n\t\t\t\t\tName: \"int\",\n\t\t\t\t\tT:    \"int\",\n\t\t\t\t\tAttributes: []*TypeAttr{\n\t\t\t\t\t\t{Name: \"size\", Kind: reflect.Int, Required: false},\n\t\t\t\t\t\t{Name: \"unsigned\", Kind: reflect.Bool, Required: false},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"varchar\",\n\t\t\t\t\tT:    \"varchar\",\n\t\t\t\t\tAttributes: []*TypeAttr{\n\t\t\t\t\t\t{Name: \"size\", Kind: reflect.Int, Required: false},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"enum\",\n\t\t\t\t\tT:    \"enum\",\n\t\t\t\t\tAttributes: []*TypeAttr{\n\t\t\t\t\t\t{Name: \"values\", Kind: reflect.Slice, Required: false},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t),\n\t)\n\tvar test struct {\n\t\tParent struct {\n\t\t\tName  string `spec:\",name\"`\n\t\t\tChild struct {\n\t\t\t\tName     string `spec:\",name\"`\n\t\t\t\tFirst    *Type  `spec:\"first\"`\n\t\t\t\tSecond   *Type  `spec:\"second\"`\n\t\t\t\tThird    *Type  `spec:\"third\"`\n\t\t\t\tVarchar  *Type  `spec:\"sized\"`\n\t\t\t\tVariadic *Type  `spec:\"variadic\"`\n\t\t\t} `spec:\"child\"`\n\t\t} `spec:\"parent\"`\n\t}\n\terr := s.EvalBytes([]byte(f), &test, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"int\", test.Parent.Child.First.T)\n\trequire.EqualValues(t, \"bool\", test.Parent.Child.Second.T)\n\n\trequire.EqualValues(t, \"varchar\", test.Parent.Child.Varchar.T)\n\trequire.Len(t, test.Parent.Child.Varchar.Attrs, 1)\n\ti, err := test.Parent.Child.Varchar.Attrs[0].Int()\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, 255, i)\n\n\trequire.EqualValues(t, \"enum\", test.Parent.Child.Variadic.T)\n\trequire.Len(t, test.Parent.Child.Variadic.Attrs, 1)\n\tvs, err := test.Parent.Child.Variadic.Attrs[0].Strings()\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, []string{\"a\", \"b\", \"c\"}, vs)\n\n\trequire.EqualValues(t, \"int\", test.Parent.Child.Third.T)\n\trequire.Len(t, test.Parent.Child.Third.Attrs, 1)\n\ti, err = test.Parent.Child.Third.Attrs[0].Int()\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, 10, i)\n\n\tafter, err := s.MarshalSpec(&test)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, f, string(after))\n}\n\nfunc TestEmptyStrSQL(t *testing.T) {\n\ts := New(WithTypes(\"\", nil))\n\th := `x = sql(\"\")`\n\terr := s.EvalBytes([]byte(h), &struct{}{}, nil)\n\trequire.ErrorContains(t, err, \"empty expression\")\n}\n\nfunc TestOptionalArgs(t *testing.T) {\n\ts := New(\n\t\tWithTypes(\"block\", []*TypeSpec{\n\t\t\t{\n\t\t\t\tT:    \"float\",\n\t\t\t\tName: \"float\",\n\t\t\t\tAttributes: []*TypeAttr{\n\t\t\t\t\tPrecisionTypeAttr(),\n\t\t\t\t\tScaleTypeAttr(),\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t)\n\tf := `\nblock \"name\" {\n  arg_0 = float\n  arg_1 = float(10)\n  arg_2 = float(10,2)\n}\n`\n\tvar test struct {\n\t\tBlock struct {\n\t\t\tName string `spec:\",name\"`\n\t\t\tArg0 *Type  `spec:\"arg_0\"`\n\t\t\tArg1 *Type  `spec:\"arg_1\"`\n\t\t\tArg2 *Type  `spec:\"arg_2\"`\n\t\t} `spec:\"block\"`\n\t}\n\terr := s.EvalBytes([]byte(f), &test, nil)\n\trequire.NoError(t, err)\n\trequire.Nil(t, test.Block.Arg0.Attrs)\n\n\trequire.Len(t, test.Block.Arg1.Attrs, 1)\n\trequire.Equal(t, \"precision\", test.Block.Arg1.Attrs[0].K)\n\ti, err := test.Block.Arg1.Attrs[0].Int()\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, 10, i)\n\n\trequire.Len(t, test.Block.Arg2.Attrs, 2)\n\trequire.Equal(t, \"precision\", test.Block.Arg2.Attrs[0].K)\n\ti, err = test.Block.Arg2.Attrs[0].Int()\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, 10, i)\n\trequire.Equal(t, \"scale\", test.Block.Arg2.Attrs[1].K)\n\ti, err = test.Block.Arg2.Attrs[1].Int()\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, 2, i)\n}\n\nfunc TestQualifiedRefs(t *testing.T) {\n\th := `user \"atlas\" \"cli\" {\n\tversion = \"v0.3.9\"\n}\nv = user.atlas.cli.version\nr = user.atlas.cli\n`\n\tvar test struct {\n\t\tV string `spec:\"v\"`\n\t\tR *Ref   `spec:\"r\"`\n\t}\n\terr := New().EvalBytes([]byte(h), &test, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"v0.3.9\", test.V)\n\trequire.EqualValues(t, \"$user.atlas.cli\", test.R.V)\n}\n\nfunc TestQuotedRefs(t *testing.T) {\n\th := `\nuser \"ariel.mashraki\" {\n  username = \"a8m\"\n}\naccount \"ariga.cloud\" \"a8m.dev\" {\n  org = \"dev\"\n}\nenv \"dev\" \"a8m.dev\" {}\nenv \"prod.1\" \"a8m\" {}\n\nv = user[\"ariel.mashraki\"].username\nr = user[\"ariel.mashraki\"]\nvs = [account[\"ariga.cloud\"][\"a8m.dev\"].org]\nrs = [\n\taccount[\"ariga.cloud\"][\"a8m.dev\"],\n\tenv[\"dev\"][\"a8m.dev\"],\n\tenv[\"prod.1\"][\"a8m\"],\n]\n`\n\tvar test struct {\n\t\tV  string   `spec:\"v\"`\n\t\tR  *Ref     `spec:\"r\"`\n\t\tVs []string `spec:\"vs\"`\n\t\tRs []*Ref   `spec:\"rs\"`\n\t}\n\terr := New().EvalBytes([]byte(h), &test, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"a8m\", test.V)\n\trequire.EqualValues(t, `$user[\"ariel.mashraki\"]`, test.R.V)\n\trequire.EqualValues(t, []string{\"dev\"}, test.Vs)\n\trequire.EqualValues(t, []*Ref{\n\t\t{`$account[\"ariga.cloud\"][\"a8m.dev\"]`},\n\t\t{`$env.dev[\"a8m.dev\"]`},\n\t\t{`$env[\"prod.1\"].a8m`},\n\t}, test.Rs)\n}\n\nfunc TestInputValues(t *testing.T) {\n\th := `\nvariable \"name\" {\n  type = string\n}\n\nvariable \"default\" {\n  type = string\n  default = \"hello\"\n}\n\nvariable \"int\" {\n  type = int\n}\n\nvariable \"bool\" {\n  type = bool\n}\n\nvariable \"convert_int\" {\n  type = int\n}\n\nvariable \"convert_bool\" {\n  type = bool\n}\n\nvariable \"strings\" {\n  type = list(string)\n  default = [\"a\", \"b\"]\n  description = \"description is a valid attribute\"\n}\n\nname = var.name\ndefault = var.default\nint = var.int\nbool = var.bool\nconvert_int = var.convert_int\nconvert_bool = var.convert_bool\nstrings = var.strings\n`\n\tvar test struct {\n\t\tName        string   `spec:\"name\"`\n\t\tDefault     string   `spec:\"default\"`\n\t\tInt         int      `spec:\"int\"`\n\t\tBool        bool     `spec:\"bool\"`\n\t\tConvertInt  int      `spec:\"convert_int\"`\n\t\tConvertBool bool     `spec:\"convert_bool\"`\n\t\tStrings     []string `spec:\"strings\"`\n\t}\n\terr := New().EvalBytes([]byte(h), &test, map[string]cty.Value{\n\t\t\"name\":         cty.StringVal(\"rotemtam\"),\n\t\t\"int\":          cty.NumberIntVal(42),\n\t\t\"bool\":         cty.BoolVal(true),\n\t\t\"convert_int\":  cty.StringVal(\"1\"),\n\t\t\"convert_bool\": cty.StringVal(\"true\"),\n\t\t\"strings\":      cty.ListVal([]cty.Value{cty.StringVal(\"a\"), cty.StringVal(\"b\")}),\n\t})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"rotemtam\", test.Name)\n\trequire.EqualValues(t, \"hello\", test.Default)\n\trequire.EqualValues(t, 42, test.Int)\n\trequire.EqualValues(t, true, test.Bool)\n\trequire.EqualValues(t, 1, test.ConvertInt)\n\trequire.EqualValues(t, true, test.ConvertBool)\n\trequire.EqualValues(t, []string{\"a\", \"b\"}, test.Strings)\n}\n\nfunc TestVariable_InvalidType(t *testing.T) {\n\th := `\nvariable \"name\" {\n  type = \"int\"\n  default = \"boring\"\n}`\n\terr := New().EvalBytes([]byte(h), &struct{}{}, nil)\n\trequire.EqualError(t, err, `invalid type \"int\" for variable \"name\". Valid types are: string, number, bool, list, map, or set`)\n\n\th = `\nvariable \"name\" {\n  type = \"boring\"\n  default = \"boring\"\n}`\n\terr = New().EvalBytes([]byte(h), &struct{}{}, nil)\n\trequire.EqualError(t, err, `invalid type \"boring\" for variable \"name\". Valid types are: string, number, bool, list, map, or set`)\n}\n\nfunc TestTemplateReferences(t *testing.T) {\n\tvar (\n\t\td struct {\n\t\t\tStmt1 string `spec:\"stmt1\"`\n\t\t\tStmt2 string `spec:\"stmt2\"`\n\t\t}\n\t\tb = []byte(`\ntable \"foo\" {}\n\ntable \"bar\" {\n  name = \"baz\"\n  column \"id\" {\n    type = int\n  }\n}\n\nstmt1 = <<-SQL\n   SELECT * FROM ${table.foo.name}\n  SQL\nstmt2 = <<-SQL\n   SELECT ${table.bar.column.id.name} FROM ${table.bar.name}\n  SQL\n`)\n\t)\n\trequire.NoError(t, New().EvalBytes(b, &d, nil))\n\trequire.Equal(t, \"SELECT * FROM foo\", strings.TrimSpace(d.Stmt1))\n\trequire.Equal(t, \"SELECT id FROM baz\", strings.TrimSpace(d.Stmt2))\n\n\terr := New().EvalBytes([]byte(`v = \"${unknown}\"`), &d, nil)\n\trequire.EqualError(t, err, `:1,8-15: Unknown variable; There is no variable named \"unknown\".`)\n}\n"
  },
  {
    "path": "schemahcl/extension.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/zclconf/go-cty/cty\"\n\t\"github.com/zclconf/go-cty/cty/gocty\"\n)\n\n// Remainer is the interface that is implemented by types that can store\n// additional attributes and children resources.\ntype Remainer interface {\n\t// Remain returns a resource representing any extra children and attributes\n\t// that are related to the struct but were not mapped to any of its fields.\n\tRemain() *Resource\n}\n\n// DefaultExtension can be embedded in structs that need basic default behavior.\n// For instance, DefaultExtension implements Remainer, and has a private *Resource\n// field that can store additional attributes and children that do not match the\n// structs fields.\ntype DefaultExtension struct {\n\tExtra Resource\n}\n\n// Remain implements the Remainer interface.\nfunc (d *DefaultExtension) Remain() *Resource {\n\treturn &d.Extra\n}\n\n// Attr returns the Attr by the provided name and reports whether it was found.\nfunc (d *DefaultExtension) Attr(name string) (*Attr, bool) {\n\treturn d.Extra.Attr(name)\n}\n\ntype registry map[string]any\n\nvar (\n\textensions   = make(registry)\n\textensionsMu sync.RWMutex\n)\n\nfunc (r registry) lookup(ext any) (string, bool) {\n\textensionsMu.RLock()\n\tdefer extensionsMu.RUnlock()\n\tfor k, v := range r {\n\t\tif reflect.TypeOf(ext) == reflect.TypeOf(v) {\n\t\t\treturn k, true\n\t\t}\n\t}\n\treturn \"\", false\n}\n\n// implementers returns a slice of the names of the extensions that implement i.\nfunc (r registry) implementers(i reflect.Type) ([]string, error) {\n\tif i.Kind() != reflect.Interface {\n\t\treturn nil, fmt.Errorf(\"schemahcl: expected interface got %s\", i.Kind())\n\t}\n\tvar names []string\n\tfor name, typ := range r {\n\t\tif reflect.TypeOf(typ).Implements(i) {\n\t\t\tnames = append(names, name)\n\t\t}\n\t}\n\treturn names, nil\n}\n\n// Register records the type of ext in the global extension registry.\n// If Register is called twice with the same name or if ext is nil,\n// it panics.\nfunc Register(name string, ext any) {\n\textensionsMu.Lock()\n\tdefer extensionsMu.Unlock()\n\tif ext == nil {\n\t\tpanic(\"schemahcl: Register extension is nil\")\n\t}\n\tif _, dup := extensions[name]; dup {\n\t\tpanic(\"schemahcl: Register called twice for type \" + name)\n\t}\n\textensions[name] = ext\n}\n\n// As reads the attributes and children resources of the resource into the target struct.\nfunc (r *Resource) As(target any) error {\n\tif err := validateStructPtr(target); err != nil {\n\t\treturn err\n\t}\n\treturn r.as(target)\n}\n\nvar typeRange = reflect.TypeOf(&hcl.Range{})\n\n// As reads the attributes and children resources of the resource into the target struct.\nfunc (r *Resource) as(target any) error {\n\texistingAttrs, existingChildren := existingElements(r)\n\tvar seenName, seenQualifier, setRange bool\n\tv := reflect.ValueOf(target).Elem()\n\tfor _, ft := range specFields(target) {\n\t\tfield := v.FieldByName(ft.Name)\n\t\tswitch {\n\t\tcase ft.isName() && !hasAttr(r, ft.tag):\n\t\t\tif seenName {\n\t\t\t\treturn errors.New(\"schemahcl: extension must have only one isName field\")\n\t\t\t}\n\t\t\tseenName = true\n\t\t\tif field.Kind() != reflect.String {\n\t\t\t\treturn errors.New(\"schemahcl: extension isName field must be of type string\")\n\t\t\t}\n\t\t\tfield.SetString(r.Name)\n\t\tcase ft.isQualifier():\n\t\t\tif seenQualifier {\n\t\t\t\treturn errors.New(\"schemahcl: extension must have only one qualifier field\")\n\t\t\t}\n\t\t\tseenQualifier = true\n\t\t\tfield.SetString(r.Qualifier)\n\t\tcase ft.isRange() && !hasAttr(r, ft.tag):\n\t\t\tif field.Type() != typeRange {\n\t\t\t\treturn fmt.Errorf(\"schemahcl: expected field %q to be of type *hcl.Range: %v\", ft.Name, field.Type())\n\t\t\t}\n\t\t\tif r.rang != nil {\n\t\t\t\tsetRange = true\n\t\t\t\tfield.Set(reflect.ValueOf(r.rang))\n\t\t\t}\n\t\tcase hasAttr(r, ft.tag):\n\t\t\tattr, _ := r.Attr(ft.tag)\n\t\t\tif err := setField(field, attr); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdelete(existingAttrs, attr.K)\n\t\tcase ft.isInterfaceSlice():\n\t\t\telem := field.Type().Elem()\n\t\t\timpls, err := extensions.implementers(elem)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tchildren := childrenOfType(r, impls...)\n\t\t\tslc := reflect.MakeSlice(reflect.SliceOf(elem), 0, len(children))\n\t\t\tfor _, c := range children {\n\t\t\t\ttyp, ok := extensions[c.Type]\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"extension %q not registered\", c.Type)\n\t\t\t\t}\n\t\t\t\tn := reflect.New(reflect.TypeOf(typ).Elem())\n\t\t\t\text := n.Interface()\n\t\t\t\tif err := c.as(ext); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tslc = reflect.Append(slc, reflect.ValueOf(ext))\n\t\t\t}\n\t\t\tfield.Set(slc)\n\t\t\tfor _, i := range impls {\n\t\t\t\tdelete(existingChildren, i)\n\t\t\t}\n\t\tcase ft.isInterface():\n\t\t\timpls, err := extensions.implementers(ft.Type)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tchildren := childrenOfType(r, impls...)\n\t\t\tif len(children) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(children) > 1 {\n\t\t\t\treturn fmt.Errorf(\"more than one blocks implement %q\", ft.Type)\n\t\t\t}\n\t\t\tc := children[0]\n\t\t\ttyp, ok := extensions[c.Type]\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"extension %q not registered\", c.Type)\n\t\t\t}\n\t\t\tn := reflect.New(reflect.TypeOf(typ).Elem())\n\t\t\text := n.Interface()\n\t\t\tif err := c.as(ext); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfield.Set(n)\n\t\tcase isResourceSlice(field.Type()):\n\t\t\tif err := setChildSlice(field, childrenOfType(r, ft.tag)); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdelete(existingChildren, ft.tag)\n\t\tcase isSingleResource(field.Type()):\n\t\t\tc := childrenOfType(r, ft.tag)\n\t\t\tif len(c) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvar (\n\t\t\t\tres = c[0]\n\t\t\t\tn   reflect.Value\n\t\t\t)\n\t\t\tswitch field.Type().Kind() {\n\t\t\tcase reflect.Struct:\n\t\t\t\tn = reflect.New(field.Type())\n\t\t\t\text := n.Interface()\n\t\t\t\tif err := res.as(ext); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tn = n.Elem()\n\t\t\tcase reflect.Pointer:\n\t\t\t\tn = reflect.New(field.Type().Elem())\n\t\t\t\text := n.Interface()\n\t\t\t\tif err := res.as(ext); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tfield.Set(n)\n\t\t\tdelete(existingChildren, ft.tag)\n\t\t}\n\t}\n\trem, ok := target.(Remainer)\n\tif !ok {\n\t\treturn nil\n\t}\n\textras := rem.Remain()\n\tfor attrName := range existingAttrs {\n\t\tattr, ok := r.Attr(attrName)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"schemahcl: expected attr %q to exist\", attrName)\n\t\t}\n\t\textras.SetAttr(attr)\n\t}\n\tfor childType := range existingChildren {\n\t\tchildren := childrenOfType(r, childType)\n\t\textras.Children = append(extras.Children, children...)\n\t}\n\t// In case the resource contains a remain (DefaultExtension) and\n\t// the range was not explicitly set, attach to it the position.\n\tif r.rang != nil && rem.Remain() != nil && !setRange {\n\t\trem.Remain().SetRange(r.rang)\n\t}\n\treturn nil\n}\n\n// FinalName returns the final name for the resource by examining the struct tags for\n// the extension of the Resource's type. If no such extension is registered or the\n// extension struct does not have a name field, an error is returned.\nfunc (r *Resource) FinalName() (string, error) {\n\textensionsMu.RLock()\n\tdefer extensionsMu.RUnlock()\n\tt, ok := extensions[r.Type]\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"no extension registered for %q\", r.Type)\n\t}\n\tfor _, fd := range specFields(t) {\n\t\tif fd.isName() {\n\t\t\tif fd.tag != \"\" {\n\t\t\t\tname, ok := r.Attr(fd.tag)\n\t\t\t\tif ok {\n\t\t\t\t\treturn name.String()\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn r.Name, nil\n\t\t}\n\t}\n\treturn \"\", fmt.Errorf(\"extension %q has no name field\", r.Type)\n}\n\nfunc validateStructPtr(target any) error {\n\ttypeOf := reflect.TypeOf(target)\n\tif typeOf.Kind() != reflect.Ptr {\n\t\treturn errors.New(\"schemahcl: expected target to be a pointer\")\n\t}\n\tif typeOf.Elem().Kind() != reflect.Struct {\n\t\treturn errors.New(\"schemahcl: expected target to be a pointer to a struct\")\n\t}\n\treturn nil\n}\n\nfunc existingElements(r *Resource) (attrs, children map[string]struct{}) {\n\tattrs, children = make(map[string]struct{}), make(map[string]struct{})\n\tfor _, ea := range r.Attrs {\n\t\tattrs[ea.K] = struct{}{}\n\t}\n\tfor _, ec := range r.Children {\n\t\tchildren[ec.Type] = struct{}{}\n\t}\n\treturn\n}\n\nfunc setChildSlice(field reflect.Value, children []*Resource) error {\n\tif field.Type().Kind() != reflect.Slice {\n\t\treturn fmt.Errorf(\"schemahcl: expected field to be of kind slice\")\n\t}\n\tif len(children) == 0 {\n\t\treturn nil\n\t}\n\ttyp := field.Type().Elem()\n\tslc := reflect.MakeSlice(reflect.SliceOf(typ), 0, len(children))\n\tfor _, c := range children {\n\t\tn := reflect.New(typ.Elem())\n\t\text := n.Interface()\n\t\tif err := c.as(ext); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tslc = reflect.Append(slc, reflect.ValueOf(ext))\n\t}\n\tfield.Set(slc)\n\treturn nil\n}\n\nfunc setField(field reflect.Value, attr *Attr) error {\n\tswitch field.Kind() {\n\tcase reflect.Slice:\n\t\treturn setSliceAttr(field, attr)\n\tcase reflect.String:\n\t\ts, err := attr.String()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"value of attr %q cannot be read as string: %w\", attr.K, err)\n\t\t}\n\t\tfield.SetString(s)\n\tcase reflect.Int, reflect.Int64:\n\t\ti, err := attr.Int()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"value of attr %q cannot be read as integer: %w\", attr.K, err)\n\t\t}\n\t\tfield.SetInt(int64(i))\n\tcase reflect.Bool:\n\t\tb, err := attr.Bool()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"value of attr %q cannot be read as bool: %w\", attr.K, err)\n\t\t}\n\t\tfield.SetBool(b)\n\tcase reflect.Ptr:\n\t\tif err := setPtr(field, attr.V); err != nil {\n\t\t\treturn fmt.Errorf(\"set field %q: %w\", attr.K, err)\n\t\t}\n\tcase reflect.Interface:\n\t\tfield.Set(reflect.ValueOf(attr.V))\n\tcase reflect.Map:\n\t\tif attr.V.CanIterateElements() {\n\t\t\tfield.Set(reflect.ValueOf(attr.V.AsValueMap()))\n\t\t\treturn nil\n\t\t}\n\t\tfallthrough\n\tdefault:\n\t\tif err := gocty.FromCtyValue(attr.V, field.Addr().Interface()); err != nil {\n\t\t\treturn fmt.Errorf(\"set field %q of type %T: %w\", attr.K, field, err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc setPtr(field reflect.Value, cv cty.Value) error {\n\trt := reflect.TypeOf(cv)\n\tif field.Type() == rt {\n\t\tfield.Set(reflect.ValueOf(cv))\n\t\treturn nil\n\t}\n\t// If we are setting a Type field handle RawExpr and Ref specifically.\n\tif _, ok := field.Interface().(*Type); ok {\n\t\tif !cv.Type().IsCapsuleType() {\n\t\t\treturn fmt.Errorf(\"unexpected type %s\", cv.Type().FriendlyName())\n\t\t}\n\t\tswitch t := cv.EncapsulatedValue().(type) {\n\t\tcase *RawExpr:\n\t\t\tfield.Set(reflect.ValueOf(&Type{\n\t\t\t\tT:     t.X,\n\t\t\t\tIsRaw: true,\n\t\t\t}))\n\t\t\treturn nil\n\t\tcase *Ref:\n\t\t\tfield.Set(reflect.ValueOf(&Type{\n\t\t\t\tT:     t.V,\n\t\t\t\tIsRef: true,\n\t\t\t}))\n\t\t\treturn nil\n\t\t}\n\t}\n\tif field.IsNil() {\n\t\tfield.Set(reflect.New(field.Type().Elem()))\n\t}\n\tswitch e := field.Interface().(type) {\n\tcase *Ref:\n\t\tswitch {\n\t\tcase cv.Type() == cty.String:\n\t\t\te.V = cv.AsString()\n\t\tcase cv.Type().IsCapsuleType():\n\t\t\tref, ok := cv.EncapsulatedValue().(*Ref)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"schemahcl: expected value to be a *Ref, got: %T\", cv.EncapsulatedValue())\n\t\t\t}\n\t\t\te.V = ref.V\n\t\t}\n\tdefault:\n\t\tif err := gocty.FromCtyValue(cv, e); err != nil {\n\t\t\treturn fmt.Errorf(\"converting cty.Value to %T: %w\", e, err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// setSliceAttr sets the value of attr to the slice field. This function expects both the target field\n// and the source attr to be slices.\nfunc setSliceAttr(field reflect.Value, attr *Attr) error {\n\tif !attr.V.Type().IsListType() && !attr.V.Type().IsTupleType() {\n\t\treturn fmt.Errorf(\"schemahcl: field is of type slice but attr %q is type: %s\", attr.K, attr.V.Type().FriendlyName())\n\t}\n\ttyp := field.Type().Elem()\n\tslc := reflect.MakeSlice(reflect.SliceOf(typ), 0, attr.V.LengthInt())\n\tswitch typ.Kind() {\n\tcase reflect.String:\n\t\ts, err := attr.Strings()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot read attribute %q of type %q as string list: %w\", attr.K, attr.V.Type().FriendlyName(), err)\n\t\t}\n\t\tfor _, item := range s {\n\t\t\tslc = reflect.Append(slc, reflect.ValueOf(item))\n\t\t}\n\tcase reflect.Bool:\n\t\tbools, err := attr.Bools()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot read attribute %q as bool list: %w\", attr.K, err)\n\t\t}\n\t\tfor _, item := range bools {\n\t\t\tslc = reflect.Append(slc, reflect.ValueOf(item))\n\t\t}\n\tcase reflect.Ptr:\n\t\tif typ != reflect.TypeOf(&Ref{}) {\n\t\t\treturn fmt.Errorf(\"only pointers to refs supported, got %s\", typ)\n\t\t}\n\t\tfor _, v := range attr.V.AsValueSlice() {\n\t\t\tswitch {\n\t\t\tcase v.Type().IsCapsuleType():\n\t\t\t\tslc = reflect.Append(slc, reflect.ValueOf(v.EncapsulatedValue().(*Ref)))\n\t\t\tcase isRef(v):\n\t\t\t\tslc = reflect.Append(slc, reflect.ValueOf(&Ref{V: v.GetAttr(\"__ref\").AsString()}))\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"schemahcl: unsupported type %s in slice\", v.Type().FriendlyName())\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"slice of unsupported kind: %q\", typ.Kind())\n\t}\n\tfield.Set(slc)\n\treturn nil\n}\n\n// Scan reads the Extension into the Resource. Scan will override the Resource\n// name or type if they are set for the extension.\nfunc (r *Resource) Scan(ext any) error {\n\tif lookup, ok := extensions.lookup(ext); ok {\n\t\tr.Type = lookup\n\t}\n\tv := indirect(reflect.ValueOf(ext))\n\tfor _, ft := range specFields(ext) {\n\t\tif !ft.IsExported() {\n\t\t\tcontinue\n\t\t}\n\t\tswitch field := v.FieldByName(ft.Name); {\n\t\tcase ft.omitempty() && isEmpty(field):\n\t\tcase ft.isName():\n\t\t\tif field.Kind() != reflect.String {\n\t\t\t\treturn errors.New(\"schemahcl: extension name field must be string\")\n\t\t\t}\n\t\t\tr.Name = field.String()\n\t\tcase ft.isQualifier():\n\t\t\tif field.Kind() != reflect.String {\n\t\t\t\treturn errors.New(\"schemahcl: extension qualifier field must be string\")\n\t\t\t}\n\t\t\tr.Qualifier = field.String()\n\t\tcase isResourceSlice(field.Type()):\n\t\t\tfor i := 0; i < field.Len(); i++ {\n\t\t\t\text := field.Index(i).Interface()\n\t\t\t\tchild := &Resource{}\n\t\t\t\tif err := child.Scan(ext); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tchild.Type = ft.tag\n\t\t\t\tr.Children = append(r.Children, child)\n\t\t\t}\n\t\tcase isSingleResource(field.Type()):\n\t\t\tif k := field.Kind(); k == reflect.Struct && field.IsZero() || k == reflect.Pointer && field.IsNil() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\text := field.Interface()\n\t\t\tchild := &Resource{}\n\t\t\tif err := child.Scan(ext); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tchild.Type = ft.tag\n\t\t\tr.Children = append(r.Children, child)\n\t\tcase field.Kind() == reflect.Ptr:\n\t\t\tif field.IsNil() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif err := scanPtr(ft.tag, r, field); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := scanAttr(ft.tag, r, field); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\trem, ok := ext.(Remainer)\n\tif !ok {\n\t\treturn nil\n\t}\n\textra := rem.Remain()\n\tfor _, attr := range extra.Attrs {\n\t\tr.SetAttr(attr)\n\t}\n\tr.Children = append(r.Children, extra.Children...)\n\treturn nil\n}\n\nfunc scanPtr(key string, r *Resource, field reflect.Value) error {\n\tattr := &Attr{K: key}\n\tswitch e := field.Interface().(type) {\n\tcase *Ref:\n\t\tattr.V = cty.CapsuleVal(ctyRefType, e)\n\tcase *Type:\n\t\tattr.V = cty.CapsuleVal(ctyTypeSpec, e)\n\tdefault:\n\t\tt, err := gocty.ImpliedType(e)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"schemahcl: cannot infer type for field %q when scanning pointer: %w\", key, err)\n\t\t}\n\t\tattr.V, err = gocty.ToCtyValue(e, t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"schemahcl: cannot convert value for field %q: %w\", key, err)\n\t\t}\n\t}\n\tr.SetAttr(attr)\n\treturn nil\n}\n\nfunc scanAttr(key string, r *Resource, field reflect.Value) error {\n\tswitch k := field.Kind(); {\n\tcase k == reflect.Interface:\n\t\tif field.IsNil() {\n\t\t\tbreak\n\t\t}\n\t\ti := field.Interface()\n\t\tv, ok := i.(cty.Value)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"schemahcl: unsupported interface type %T for field %q\", i, key)\n\t\t}\n\t\tr.SetAttr(&Attr{K: key, V: v})\n\tcase field.Type() == reflect.TypeOf([]*Ref{}):\n\t\tif field.Len() > 0 {\n\t\t\tr.SetAttr(RefsAttr(key, field.Interface().([]*Ref)...))\n\t\t}\n\tcase k == reflect.Int, k == reflect.Int64:\n\t\tr.SetAttr(Int64Attr(key, field.Int()))\n\tcase k == reflect.Struct:\n\t\tif v, ok := field.Interface().(cty.Value); ok && v.IsNull() {\n\t\t\tbreak\n\t\t}\n\t\tfallthrough\n\tdefault:\n\t\tt, err := gocty.ImpliedType(field.Interface())\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"schemahcl: cannot infer type for field %q when scanning attribute: %w\", key, err)\n\t\t}\n\t\tv, err := gocty.ToCtyValue(field.Interface(), t)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"schemahcl: cannot convert value for field %q: %w\", key, err)\n\t\t}\n\t\tr.SetAttr(&Attr{\n\t\t\tK: key,\n\t\t\tV: v,\n\t\t})\n\t}\n\treturn nil\n}\n\n// specCache holds a cache for type-spec fields descriptions.\nvar specCache sync.Map\n\n// specFields uses reflection to find struct fields that are tagged with \"spec\"\n// and returns a list of mappings from the tag to the field name.\nfunc specFields(ext any) []fieldDesc {\n\tt := indirect(reflect.TypeOf(ext))\n\tif d, ok := specCache.Load(t); ok {\n\t\treturn d.([]fieldDesc)\n\t}\n\tvar fields []fieldDesc\n\tfor i := 0; i < t.NumField(); i++ {\n\t\tf := t.Field(i)\n\t\ttag, ok := f.Tag.Lookup(\"spec\")\n\t\tif !ok || tag == \"-\" {\n\t\t\tcontinue\n\t\t}\n\t\td := fieldDesc{tag: tag, StructField: f}\n\t\tif idx := strings.IndexByte(tag, ','); idx != -1 {\n\t\t\td.tag, d.options = tag[:idx], tag[idx+1:]\n\t\t}\n\t\tfields = append(fields, d)\n\t}\n\tspecCache.Store(t, fields)\n\treturn fields\n}\n\nfunc isEmpty(v reflect.Value) bool {\n\tswitch v.Kind() {\n\tcase reflect.Array, reflect.Map, reflect.Slice, reflect.String:\n\t\treturn v.Len() == 0\n\tcase reflect.Bool:\n\t\treturn !v.Bool()\n\tcase reflect.Interface, reflect.Ptr:\n\t\treturn v.IsNil()\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn v.Int() == 0\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:\n\t\treturn v.Uint() == 0\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn v.Float() == 0\n\t}\n\treturn false\n}\n\ntype fieldDesc struct {\n\ttag     string // tag name.\n\toptions string // rest of the options.\n\treflect.StructField\n}\n\nfunc (f fieldDesc) isName() bool { return f.is(\"name\") }\n\nfunc (f fieldDesc) isQualifier() bool { return f.is(\"qualifier\") }\n\nfunc (f fieldDesc) isRange() bool { return f.is(\"range\") }\n\nfunc (f fieldDesc) omitempty() bool { return f.is(\"omitempty\") }\n\nfunc (f fieldDesc) is(t string) bool {\n\tfor _, opt := range strings.Split(f.options, \",\") {\n\t\tif opt == t {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (f fieldDesc) isInterfaceSlice() bool {\n\treturn f.Type.Kind() == reflect.Slice && f.Type.Elem().Kind() == reflect.Interface\n}\n\nfunc (f fieldDesc) isInterface() bool {\n\treturn f.Type.Kind() == reflect.Interface\n}\n\nfunc childrenOfType(r *Resource, types ...string) []*Resource {\n\tvar out []*Resource\n\tfor _, c := range r.Children {\n\t\tfor _, typ := range types {\n\t\t\tif c.Type == typ {\n\t\t\t\tout = append(out, c)\n\t\t\t}\n\t\t}\n\t}\n\treturn out\n}\n\nfunc isSingleResource(t reflect.Type) bool {\n\tif t.Kind() == reflect.Ptr {\n\t\tt = t.Elem()\n\t}\n\tif t.Kind() != reflect.Struct {\n\t\treturn false\n\t}\n\tfor i := 0; i < t.NumField(); i++ {\n\t\tf := t.Field(i)\n\t\tif _, ok := f.Tag.Lookup(\"spec\"); ok {\n\t\t\treturn true\n\t\t}\n\t\tif f.Type == reflect.TypeOf(DefaultExtension{}) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc isResourceSlice(t reflect.Type) bool {\n\tif t.Kind() != reflect.Slice {\n\t\treturn false\n\t}\n\treturn isSingleResource(t.Elem())\n}\n\nfunc hasAttr(r *Resource, name string) bool {\n\t_, ok := r.Attr(name)\n\treturn ok\n}\n\ntype rtype[T any] interface {\n\tElem() T\n\tKind() reflect.Kind\n}\n\n// indirect returns the type at the end of indirection.\nfunc indirect[T rtype[T]](t T) T {\n\tfor t.Kind() == reflect.Ptr {\n\t\tt = t.Elem()\n\t}\n\treturn t\n}\n"
  },
  {
    "path": "schemahcl/extension_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl_test\n\nimport (\n\t\"testing\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\ntype OwnerBlock struct {\n\tschemahcl.DefaultExtension\n\tID        string    `spec:\",name\"`\n\tFirstName string    `spec:\"first_name\"`\n\tBorn      int       `spec:\"born\"`\n\tActive    bool      `spec:\"active\"`\n\tBoolPtr   *bool     `spec:\"bool_ptr\"`\n\tOmitBool1 bool      `spec:\"omit_bool1,omitempty\"`\n\tOmitBool2 bool      `spec:\"omit_bool2,omitempty\"`\n\tLit       cty.Value `spec:\"lit\"`\n}\n\ntype PetBlock struct {\n\tschemahcl.DefaultExtension\n\tID        string        `spec:\",name\"`\n\tBreed     string        `spec:\"breed\"`\n\tBorn      int           `spec:\"born\"`\n\tOwners    []*OwnerBlock `spec:\"owner\"`\n\tRoleModel *PetBlock     `spec:\"role_model\"`\n}\n\nfunc TestInvalidExt(t *testing.T) {\n\tr := &schemahcl.Resource{}\n\terr := r.As(1)\n\trequire.EqualError(t, err, \"schemahcl: expected target to be a pointer\")\n\tvar p *string\n\terr = r.As(p)\n\trequire.EqualError(t, err, \"schemahcl: expected target to be a pointer to a struct\")\n}\n\nfunc TestExtension(t *testing.T) {\n\tschemahcl.Register(\"owner\", &OwnerBlock{})\n\toriginal := &schemahcl.Resource{\n\t\tName: \"name\",\n\t\tType: \"owner\",\n\t\tAttrs: []*schemahcl.Attr{\n\t\t\tschemahcl.StringAttr(\"first_name\", \"tzuri\"),\n\t\t\tschemahcl.IntAttr(\"born\", 2019),\n\t\t\tschemahcl.BoolAttr(\"active\", true),\n\t\t\tschemahcl.BoolAttr(\"bool_ptr\", true),\n\t\t\tschemahcl.BoolAttr(\"omit_bool1\", true),\n\t\t\tschemahcl.StringAttr(\"lit\", \"1000\"),\n\t\t\tschemahcl.BoolAttr(\"extra\", true),\n\t\t},\n\t\tChildren: []*schemahcl.Resource{\n\t\t\t{\n\t\t\t\tName: \"extra\",\n\t\t\t\tType: \"extra\",\n\t\t\t},\n\t\t},\n\t}\n\towner := OwnerBlock{}\n\terr := original.As(&owner)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"tzuri\", owner.FirstName)\n\trequire.EqualValues(t, \"name\", owner.ID)\n\trequire.EqualValues(t, 2019, owner.Born)\n\trequire.EqualValues(t, true, owner.Active)\n\trequire.NotNil(t, owner.BoolPtr)\n\trequire.EqualValues(t, true, *owner.BoolPtr)\n\trequire.EqualValues(t, cty.StringVal(\"1000\"), owner.Lit)\n\tattr, ok := owner.Remain().Attr(\"extra\")\n\trequire.True(t, ok)\n\teb, err := attr.Bool()\n\trequire.NoError(t, err)\n\trequire.True(t, eb)\n\n\tscan := &schemahcl.Resource{}\n\terr = scan.Scan(&owner)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, original, scan)\n}\n\nfunc TestNested(t *testing.T) {\n\tschemahcl.Register(\"pet\", &PetBlock{})\n\tpet := &schemahcl.Resource{\n\t\tName: \"donut\",\n\t\tType: \"pet\",\n\t\tAttrs: []*schemahcl.Attr{\n\t\t\tschemahcl.StringAttr(\"breed\", \"golden retriever\"),\n\t\t\tschemahcl.IntAttr(\"born\", 2002),\n\t\t},\n\t\tChildren: []*schemahcl.Resource{\n\t\t\t{\n\t\t\t\tName: \"rotemtam\",\n\t\t\t\tType: \"owner\",\n\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\tschemahcl.StringAttr(\"first_name\", \"rotem\"),\n\t\t\t\t\tschemahcl.IntAttr(\"born\", 1985),\n\t\t\t\t\tschemahcl.BoolAttr(\"active\", true),\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"gonnie\",\n\t\t\t\tType: \"role_model\",\n\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\tschemahcl.StringAttr(\"breed\", \"golden retriever\"),\n\t\t\t\t\tschemahcl.IntAttr(\"born\", 1998),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tpb := PetBlock{}\n\terr := pet.As(&pb)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, PetBlock{\n\t\tID:    \"donut\",\n\t\tBreed: \"golden retriever\",\n\t\tBorn:  2002,\n\t\tOwners: []*OwnerBlock{\n\t\t\t{ID: \"rotemtam\", FirstName: \"rotem\", Born: 1985, Active: true},\n\t\t},\n\t\tRoleModel: &PetBlock{\n\t\t\tID:    \"gonnie\",\n\t\t\tBreed: \"golden retriever\",\n\t\t\tBorn:  1998,\n\t\t},\n\t}, pb)\n\tscan := &schemahcl.Resource{}\n\terr = scan.Scan(&pb)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, pet, scan)\n\tname, err := pet.FinalName()\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"donut\", name)\n}\n\nfunc TestRef(t *testing.T) {\n\ttype A struct {\n\t\tName string         `spec:\",name\"`\n\t\tUser *schemahcl.Ref `spec:\"user\"`\n\t}\n\tschemahcl.Register(\"a\", &A{})\n\tresource := &schemahcl.Resource{\n\t\tName: \"x\",\n\t\tType: \"a\",\n\t\tAttrs: []*schemahcl.Attr{\n\t\t\tschemahcl.RefAttr(\"user\", &schemahcl.Ref{V: \"$user.rotemtam\"}),\n\t\t},\n\t}\n\tvar a A\n\terr := resource.As(&a)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, &schemahcl.Ref{V: \"$user.rotemtam\"}, a.User)\n\tscan := &schemahcl.Resource{}\n\terr = scan.Scan(&a)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, resource, scan)\n}\n\nfunc TestListRef(t *testing.T) {\n\ttype B struct {\n\t\tName  string           `spec:\",name\"`\n\t\tUsers []*schemahcl.Ref `spec:\"users\"`\n\t}\n\tschemahcl.Register(\"b\", &B{})\n\tresource := &schemahcl.Resource{\n\t\tName: \"x\",\n\t\tType: \"b\",\n\t\tAttrs: []*schemahcl.Attr{\n\t\t\tschemahcl.RefsAttr(\n\t\t\t\t\"users\",\n\t\t\t\t&schemahcl.Ref{V: \"$user.a8m\"},\n\t\t\t\t&schemahcl.Ref{V: \"$user.rotemtam\"},\n\t\t\t),\n\t\t},\n\t}\n\n\tvar b B\n\terr := resource.As(&b)\n\trequire.NoError(t, err)\n\trequire.Len(t, b.Users, 2)\n\trequire.EqualValues(t, []*schemahcl.Ref{\n\t\t{V: \"$user.a8m\"},\n\t\t{V: \"$user.rotemtam\"},\n\t}, b.Users)\n\tscan := &schemahcl.Resource{}\n\terr = scan.Scan(&b)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, resource, scan)\n}\n\nfunc TestNameAttr(t *testing.T) {\n\ttype Named struct {\n\t\tName string `spec:\"name,name\"`\n\t}\n\tschemahcl.Register(\"named\", &Named{})\n\tresource := &schemahcl.Resource{\n\t\tName: \"id\",\n\t\tType: \"named\",\n\t\tAttrs: []*schemahcl.Attr{\n\t\t\tschemahcl.StringAttr(\"name\", \"atlas\"),\n\t\t},\n\t}\n\tvar tgt Named\n\terr := resource.As(&tgt)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"atlas\", tgt.Name)\n\tname, err := resource.FinalName()\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, name, \"atlas\")\n}\n"
  },
  {
    "path": "schemahcl/schemahcl.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"slices\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/hashicorp/hcl/v2/hclsyntax\"\n\t\"github.com/hashicorp/hcl/v2/hclwrite\"\n\t\"github.com/zclconf/go-cty/cty\"\n\t\"github.com/zclconf/go-cty/cty/function\"\n)\n\ntype (\n\t// Config configures an unmarshaling.\n\tConfig struct {\n\t\ttypes            []*TypeSpec\n\t\tvars             map[string]cty.Value\n\t\tfuncs            map[string]function.Function\n\t\tpathVars         map[string]map[string]cty.Value\n\t\tpathFuncs        map[string]map[string]function.Function\n\t\tvalidator        func() SchemaValidator\n\t\tdatasrc, initblk map[string]BlockFunc\n\t\ttypedblk         map[string]map[string]BlockFunc\n\t\tlazyattrs        map[string]bool\n\t\t// Optional context to pass to dynamic block handlers,\n\t\t// such as data-sources, type-blocks, etc.\n\t\tctx     context.Context\n\t\twithPos bool\n\t}\n\t// Option configures a Config.\n\tOption func(*Config)\n)\n\n// New returns a State configured with options.\nfunc New(opts ...Option) *State {\n\tcfg := &Config{\n\t\tvars:      make(map[string]cty.Value),\n\t\tfuncs:     make(map[string]function.Function),\n\t\tpathVars:  make(map[string]map[string]cty.Value),\n\t\tpathFuncs: make(map[string]map[string]function.Function),\n\t}\n\tfor _, opt := range opts {\n\t\topt(cfg)\n\t}\n\tfor n, f := range stdFuncs() {\n\t\tcfg.funcs[n] = f\n\t}\n\treturn &State{\n\t\tconfig: cfg,\n\t\tnewCtx: func() *hcl.EvalContext {\n\t\t\treturn stdTypes(&hcl.EvalContext{\n\t\t\t\tVariables: cfg.vars,\n\t\t\t\tFunctions: cfg.funcs,\n\t\t\t})\n\t\t},\n\t}\n}\n\n// WithContext allows passing a context to Eval stage.\n// If provided, data source and type-block handlers will\n// have access to this context.\nfunc WithContext(ctx context.Context) Option {\n\treturn func(c *Config) {\n\t\tc.ctx = ctx\n\t}\n}\n\n// WithScopedEnums configured a list of allowed ENUMs to be used in\n// the given context, block or attribute. For example, the following\n// option allows setting HASH or BTREE to the \"using\" attribute in\n// \"index\" block.\n//\n//\tWithScopedEnums(\"table.index.type\", \"HASH\", \"BTREE\")\n//\n//\ttable \"t\" {\n//\t\t...\n//\t\tindex \"i\" {\n//\t\t\ttype = HASH     // Allowed.\n//\t\t\ttype = INVALID  // Not Allowed.\n//\t\t}\n//\t}\nfunc WithScopedEnums[T interface{ ~string }](path string, enums ...T) Option {\n\treturn func(c *Config) {\n\t\tvars := make(map[string]cty.Value, len(enums))\n\t\tfor i := range enums {\n\t\t\tvars[string(enums[i])] = cty.StringVal(string(enums[i]))\n\t\t}\n\t\tc.pathVars[path] = vars\n\t}\n}\n\n// WithPos attaches parse positions to returned Resources and Attrs.\nfunc WithPos() Option {\n\treturn func(c *Config) {\n\t\tc.withPos = true\n\t}\n}\n\n// WithVariables registers a list of variables to be injected into the context.\nfunc WithVariables(vars map[string]cty.Value) Option {\n\treturn func(c *Config) {\n\t\tif c.vars == nil {\n\t\t\tc.vars = make(map[string]cty.Value)\n\t\t}\n\t\tfor n, v := range vars {\n\t\t\tc.vars[n] = v\n\t\t}\n\t}\n}\n\n// WithFunctions registers a list of functions to be injected into the context.\nfunc WithFunctions(funcs map[string]function.Function) Option {\n\treturn func(c *Config) {\n\t\tif c.funcs == nil {\n\t\t\tc.funcs = make(map[string]function.Function)\n\t\t}\n\t\tfor n, f := range funcs {\n\t\t\tc.funcs[n] = f\n\t\t}\n\t}\n}\n\n// BlockFunc is the function signature for evaluating a dynamic block.\ntype BlockFunc func(context.Context, *hcl.EvalContext, *hclsyntax.Block) (cty.Value, error)\n\n// WithDataSource registers a data source name and its corresponding handler.\n// e.g., the example below registers a data source named \"text\" that returns\n// the string defined in the data source block.\n//\n//\tWithDataSource(\"text\", func(ctx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, hcl.Diagnostics) {\n//\t\tattrs, diags := b.Body.JustAttributes()\n//\t\tif diags.HasErrors() {\n//\t\t\treturn cty.NilVal, diags\n//\t\t}\n//\t\tv, diags := attrs[\"value\"].Expr.Value(ctx)\n//\t\tif diags.HasErrors() {\n//\t\t\treturn cty.NilVal, diags\n//\t\t}\n//\t\treturn cty.ObjectVal(map[string]cty.Value{\"output\": v}), nil\n//\t})\n//\n//\tdata \"text\" \"hello\" {\n//\t  value = \"hello world\"\n//\t}\nfunc WithDataSource(name string, h BlockFunc) Option {\n\treturn func(c *Config) {\n\t\tif c.datasrc == nil {\n\t\t\tc.datasrc = make(map[string]BlockFunc)\n\t\t}\n\t\tc.datasrc[name] = h\n\t}\n}\n\n// WithTypeLabelBlock registers a type-block and its label along with the corresponding handler.\n// e.g., the example below registers a typed block named \"driver\" with the label \"remote\" that\n// returns the string defined in the token attribute.\n//\n//\tWithTypeLabelBlock(\"driver\", \"remote\", func(ctx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, hcl.Diagnostics) {\n//\t\tattrs, diags := b.Body.JustAttributes()\n//\t\tif diags.HasErrors() {\n//\t\t\treturn cty.NilVal, diags\n//\t\t}\n//\t\tv, diags := attrs[\"token\"].Expr.Value(ctx)\n//\t\tif diags.HasErrors() {\n//\t\t\treturn cty.NilVal, diags\n//\t\t}\n//\t\treturn cty.ObjectVal(map[string]cty.Value{\"url\": v}), nil\n//\t})\n//\n//\tdriver \"remote\" \"hello\" {\n//\t  token = \"hello world\"\n//\t}\nfunc WithTypeLabelBlock(name, label string, h BlockFunc) Option {\n\treturn func(c *Config) {\n\t\tif c.typedblk == nil {\n\t\t\tc.typedblk = make(map[string]map[string]BlockFunc)\n\t\t}\n\t\tif c.typedblk[name] == nil {\n\t\t\tc.typedblk[name] = make(map[string]BlockFunc)\n\t\t}\n\t\tc.typedblk[name][label] = h\n\t}\n}\n\n// WithInitBlock registers a block that evaluates (first) to a cty.Value,\n// has no labels, and can be defined only once. For example:\n//\n//\tWithInitBlock(\"atlas\", func(ctx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, hcl.Diagnostics) {\n//\t\tattrs, diags := b.Body.JustAttributes()\n//\t\tif diags.HasErrors() {\n//\t\t\treturn cty.NilVal, diags\n//\t\t}\n//\t\tv, diags := attrs[\"modules\"].Expr.Value(ctx)\n//\t\tif diags.HasErrors() {\n//\t\t\treturn cty.NilVal, diags\n//\t\t}\n//\t\treturn cty.ObjectVal(map[string]cty.Value{\"modules\": v}), nil\n//\t})\nfunc WithInitBlock(name string, h BlockFunc) Option {\n\treturn func(c *Config) {\n\t\tif c.initblk == nil {\n\t\t\tc.initblk = make(map[string]BlockFunc)\n\t\t}\n\t\tc.initblk[name] = h\n\t}\n}\n\n// WithTypes configures the given types as identifiers in the unmarshal\n// context. The path controls where the usage of this type is allowed.\nfunc WithTypes(path string, typeSpecs []*TypeSpec) Option {\n\tvars := make(map[string]cty.Value)\n\tfuncs := make(map[string]function.Function)\n\tfor _, ts := range typeSpecs {\n\t\ttypeSpec := ts\n\t\t// If no required args exist, register the type as a variable in the HCL context.\n\t\tif len(typeFuncReqArgs(typeSpec)) == 0 {\n\t\t\ttyp := &Type{T: typeSpec.T}\n\t\t\tvars[typeSpec.Name] = cty.CapsuleVal(ctyTypeSpec, typ)\n\t\t}\n\t\t// If func args exist, register the type as a function in HCL.\n\t\tif len(typeFuncArgs(typeSpec)) > 0 {\n\t\t\tfuncs[typeSpec.Name] = typeFuncSpec(typeSpec)\n\t\t}\n\t}\n\treturn func(c *Config) {\n\t\tc.types = append(c.types, typeSpecs...)\n\t\tc.pathVars[path] = vars\n\t\tc.pathFuncs[path] = funcs\n\t}\n}\n\ntype (\n\t// SchemaValidator is the interface used for validating HCL documents.\n\tSchemaValidator interface {\n\t\tErr() error\n\t\tValidateBody(*hcl.EvalContext, *hclsyntax.Body) (func() error, error)\n\t\tValidateBlock(*hcl.EvalContext, *hclsyntax.Block) (func() error, error)\n\t\tValidateAttribute(*hcl.EvalContext, *hclsyntax.Attribute, cty.Value) error\n\t}\n\tnopValidator struct{}\n)\n\nfunc (nopValidator) Err() error { return nil }\nfunc (nopValidator) ValidateBody(*hcl.EvalContext, *hclsyntax.Body) (func() error, error) {\n\treturn func() error { return nil }, nil\n}\nfunc (nopValidator) ValidateBlock(*hcl.EvalContext, *hclsyntax.Block) (func() error, error) {\n\treturn func() error { return nil }, nil\n}\nfunc (nopValidator) ValidateAttribute(*hcl.EvalContext, *hclsyntax.Attribute, cty.Value) error {\n\treturn nil\n}\n\n// WithSchemaValidator registers a schema validator to be used during unmarshaling.\nfunc WithSchemaValidator(v func() SchemaValidator) Option {\n\treturn func(c *Config) {\n\t\tc.validator = v\n\t}\n}\n\n// Marshal returns the Atlas HCL encoding of v.\nvar Marshal = MarshalerFunc(New().MarshalSpec)\n\ntype (\n\t// State is used to evaluate and marshal Atlas HCL documents and stores a configuration for these operations.\n\tState struct {\n\t\tconfig *Config\n\t\tnewCtx func() *hcl.EvalContext\n\t}\n\t// Evaluator is the interface that wraps the Eval function.\n\tEvaluator interface {\n\t\t// Eval evaluates parsed HCL files using input variables into a schema.Realm.\n\t\tEval(*hclparse.Parser, any, map[string]cty.Value) error\n\t}\n\t// EvalFunc is an adapter that allows the use of an ordinary function as an Evaluator.\n\tEvalFunc func(*hclparse.Parser, any, map[string]cty.Value) error\n\t// Marshaler is the interface that wraps the MarshalSpec function.\n\tMarshaler interface {\n\t\t// MarshalSpec marshals the provided input into a valid Atlas HCL document.\n\t\tMarshalSpec(any) ([]byte, error)\n\t}\n\t// MarshalerFunc is the function type that is implemented by the MarshalSpec\n\t// method of the Marshaler interface.\n\tMarshalerFunc func(any) ([]byte, error)\n)\n\n// MarshalSpec implements Marshaler for Atlas HCL documents.\nfunc (s *State) MarshalSpec(v any) ([]byte, error) {\n\tr := &Resource{}\n\tif err := r.Scan(v); err != nil {\n\t\treturn nil, fmt.Errorf(\"schemahcl: failed scanning %T to resource: %w\", v, err)\n\t}\n\treturn s.encode(r)\n}\n\n// EvalOptions configures the evaluation of HCL documents.\ntype EvalOptions struct {\n\t// Variables is a map of input variables to be used during evaluation.\n\tVariables map[string]cty.Value\n\n\t// RecordPos indicates whether to record the source code positions of the\n\t// evaluated resources and attributes. It defaults to the State (Driver) config.\n\tRecordPos bool\n\n\t// Validator is the schema validator to be used during evaluation.\n\t// It defaults to the State (Driver) config.\n\tValidator SchemaValidator\n}\n\n// EvalFiles evaluates the files in the provided paths using the input variables and\n// populates v with the result.\nfunc (s *State) EvalFiles(paths []string, v any, input map[string]cty.Value) error {\n\tparser := hclparse.NewParser()\n\tfor _, path := range paths {\n\t\tif _, diag := parser.ParseHCLFile(path); diag.HasErrors() {\n\t\t\treturn diag\n\t\t}\n\t}\n\treturn s.Eval(parser, v, input)\n}\n\n// Eval evaluates the parsed HCL documents using the input variables and populates v\n// using the result.\nfunc (s *State) Eval(parsed *hclparse.Parser, v any, input map[string]cty.Value) error {\n\treturn s.EvalOptions(parsed, v, &EvalOptions{\n\t\tVariables: input,\n\t})\n}\n\n// EvalOptions evaluates the parsed HCL documents and populates v using the result.\nfunc (s *State) EvalOptions(parsed *hclparse.Parser, v any, opts *EvalOptions) error {\n\tvar (\n\t\thasVars      bool\n\t\tctx          = s.newCtx()\n\t\tfiles        = parsed.Files()\n\t\tfileNames    = make([]string, 0, len(files))\n\t\tmetaBlocks   = make(map[string][]*hclsyntax.Block, len(files))\n\t\tstaticBlocks = make([]*hclsyntax.Block, 0, len(files))\n\t\treg          = &blockDef{\n\t\t\tchildren: make(map[string]*blockDef),\n\t\t}\n\t)\n\tif ctx.Variables == nil {\n\t\tctx.Variables = make(map[string]cty.Value)\n\t}\n\tfor name, file := range files {\n\t\tfileNames = append(fileNames, name)\n\t\tif err := s.setInputVals(ctx, file.Body, opts.Variables); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbody := file.Body.(*hclsyntax.Body)\n\t\tif err := s.evalReferences(ctx, body); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tblocks := make(hclsyntax.Blocks, 0, len(body.Blocks))\n\t\tfor _, b := range body.Blocks {\n\t\t\tswitch {\n\t\t\tcase b.Type == BlockVariable:\n\t\t\t\thasVars = true\n\t\t\tcase b.Body != nil && b.Body.Attributes[forEachAttr] != nil:\n\t\t\t\tmetaBlocks[name] = append(metaBlocks[name], b)\n\t\t\tdefault:\n\t\t\t\tblocks = append(blocks, b)\n\t\t\t\treg.addChild(b, 0)\n\t\t\t}\n\t\t}\n\t\tbody.Blocks = blocks\n\t\tstaticBlocks = append(staticBlocks, blocks...)\n\t}\n\tvars, err := blockVars(staticBlocks, \"\", reg)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor k, v := range vars {\n\t\tctx.Variables[k] = v\n\t}\n\t// Semi-evaluate blocks with the for_each meta argument.\n\tif len(metaBlocks) > 0 {\n\t\tblocks := make([]*hclsyntax.Block, 0, len(metaBlocks))\n\t\tfor name, bs := range metaBlocks {\n\t\t\tfor _, b := range bs {\n\t\t\t\tnb, err := s.forEachBlocks(ctx, b)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\t// Extract the definition of the top-level is enough.\n\t\t\t\treg.addChild(b, 0)\n\t\t\t\tblocks = append(blocks, nb...)\n\t\t\t\tfiles[name].Body.(*hclsyntax.Body).Blocks = append(files[name].Body.(*hclsyntax.Body).Blocks, nb...)\n\t\t\t}\n\t\t}\n\t\tif vars, err = blockVars(blocks, \"\", reg); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor k, v := range vars {\n\t\t\tif v.IsNull() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif bs, ok := ctx.Variables[k]; !ok || bs.IsNull() {\n\t\t\t\tctx.Variables[k] = v\n\t\t\t} else {\n\t\t\t\tvs := bs.AsValueMap()\n\t\t\t\tfor k1, v1 := range v.AsValueMap() {\n\t\t\t\t\tvs[k1] = v1\n\t\t\t\t}\n\t\t\t\tctx.Variables[k] = cty.ObjectVal(vs)\n\t\t\t}\n\t\t}\n\t}\n\tspec := &Resource{}\n\tsort.Slice(fileNames, func(i, j int) bool {\n\t\treturn fileNames[i] < fileNames[j]\n\t})\n\tvar vr SchemaValidator\n\tswitch {\n\tcase opts.Validator != nil:\n\t\tvr = opts.Validator\n\tcase s.config.validator != nil:\n\t\tvr = s.config.validator()\n\t\topts.Validator = vr\n\tdefault:\n\t\tvr = &nopValidator{}\n\t\topts.Validator = vr\n\t}\n\tfor _, name := range fileNames {\n\t\tfile := files[name]\n\t\tr, err := s.resource(ctx, opts, file, reg)\n\t\tif err != nil {\n\t\t\treturn errors.Join(vr.Err(), err)\n\t\t}\n\t\tspec.Children = append(spec.Children, r.Children...)\n\t\tspec.Attrs = append(spec.Attrs, r.Attrs...)\n\t}\n\t// Validators can fail fast or accumulate errors.\n\tif err := vr.Err(); err != nil {\n\t\treturn err\n\t}\n\t// Has variables with or without default values.\n\tif hasVars {\n\t\t// In case some blocks get their names dynamically (e.g., name = var.x),\n\t\t// we need to update the references from the stub label to its final name.\n\t\tif err := patchRefs(spec); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := spec.As(v); err != nil {\n\t\treturn fmt.Errorf(\"schemahcl: failed reading spec as %T: %w\", v, err)\n\t}\n\treturn nil\n}\n\n// EvalBytes evaluates the data byte-slice as an Atlas HCL document using the input variables\n// and stores the result in v.\nfunc (s *State) EvalBytes(data []byte, v any, input map[string]cty.Value) error {\n\tparser := hclparse.NewParser()\n\tif _, diag := parser.ParseHCL(data, \"\"); diag.HasErrors() {\n\t\treturn diag\n\t}\n\treturn s.Eval(parser, v, input)\n}\n\n// addrRef maps addresses to their referenced resource.\ntype addrRef map[string]*Resource\n\n// patchRefs recursively searches for schemahcl.Ref under the provided schemahcl.Resource\n// and patches any variables with their concrete names.\nfunc patchRefs(spec *Resource) error {\n\treturn make(addrRef).patch(spec)\n}\n\nfunc (r addrRef) patch(resource *Resource) error {\n\tr.load(resource, \"\")\n\tfor _, attr := range resource.Attrs {\n\t\tif !attr.IsRef() {\n\t\t\tcontinue\n\t\t}\n\t\tref := attr.V.EncapsulatedValue().(*Ref)\n\t\treferenced, ok := r[ref.V]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"broken reference to %q\", ref.V)\n\t\t}\n\t\tif name, err := referenced.FinalName(); err == nil && name != referenced.Name {\n\t\t\tref.V = strings.ReplaceAll(ref.V, referenced.Name, name)\n\t\t}\n\t}\n\tfor _, ch := range resource.Children {\n\t\tif err := r.patch(ch); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// load the references from the children of the resource.\nfunc (r addrRef) load(res *Resource, track string) addrRef {\n\tunlabeled := 0\n\tfor _, ch := range res.Children {\n\t\tcurrent := addr(\"\", ch.Type, ch.Name, ch.Qualifier)\n\t\tif ch.Name == \"\" {\n\t\t\tcurrent += \".\" + strconv.Itoa(unlabeled)\n\t\t\tunlabeled++\n\t\t}\n\t\tif track != \"\" {\n\t\t\tcurrent = track + \".\" + current\n\t\t}\n\t\tr[current] = ch\n\t\tr.load(ch, current)\n\t}\n\treturn r\n}\n\n// resource converts the hcl file to a schemahcl.Resource.\nfunc (s *State) resource(ctx *hcl.EvalContext, opts *EvalOptions, file *hcl.File, dec *blockDef) (*Resource, error) {\n\tbody, ok := file.Body.(*hclsyntax.Body)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"schemahcl: expected remainder to be of type *hclsyntax.Body\")\n\t}\n\tcloseScope, err := opts.Validator.ValidateBody(ctx, body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tattrs, err := s.toAttrs(ctx, opts, body.Attributes, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tres := &Resource{\n\t\tAttrs:    attrs,\n\t\tChildren: make([]*Resource, 0, len(body.Blocks)),\n\t}\n\tfor _, blk := range body.Blocks {\n\t\t// variable blocks may be included in the document but are skipped in unmarshaling.\n\t\tif blk.Type == BlockVariable {\n\t\t\tcontinue\n\t\t}\n\t\tcdec := dec.child(blk.Type)\n\t\tctx, err := setLocalVars(ctx.NewChild(), blk.Body, cdec)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresource, err := s.toResource(ctx, opts, blk, []string{blk.Type}, dec.children[blk.Type])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tres.Children = append(res.Children, resource)\n\t}\n\tif err := closeScope(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn res, nil\n}\n\n// setLocalVars extends the context with the local block variables (references) so they\n// can be referenced in later stages. For example, an index block may reference its sibling\n// column blocks by their names:\n//\n//\ttable \"t\" {\n//\t  column \"c1\" { ... }\n//\t  index \"i1\" { columns = [column.c1] }\n//\t}\nfunc setLocalVars(ctx *hcl.EvalContext, b *hclsyntax.Body, dec *blockDef) (*hcl.EvalContext, error) {\n\tvars, err := blockVars(b.Blocks, \"\", dec)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch {\n\tcase ctx.Variables == nil:\n\t\tctx.Variables = vars\n\tcase len(ctx.Variables) >= len(vars):\n\t\tfor k, v := range vars {\n\t\t\tctx.Variables[k] = v\n\t\t}\n\tdefault:\n\t\tfor k, v := range ctx.Variables {\n\t\t\tvars[k] = v\n\t\t}\n\t\tctx.Variables = vars\n\t}\n\treturn ctx, nil\n}\n\n// mayScopeContext returns a new limited context for the given scope with access only\n// to variables defined by WithScopedEnums and WithTypes and references in the document.\nfunc (s *State) mayScopeContext(ctx *hcl.EvalContext, scope []string) *hcl.EvalContext {\n\tpath := strings.Join(scope, \".\")\n\tvars, ok1 := s.config.pathVars[path]\n\tfuncs, ok2 := s.config.pathFuncs[path]\n\tif !ok1 && !ok2 {\n\t\treturn ctx\n\t}\n\tnctx := ctx.NewChild()\n\t// Use the same variables/functions maps to avoid copying per scope, but return a\n\t// another child context to prevent writes from different blocks to the same maps.\n\tnctx.Variables, nctx.Functions = vars, funcs\n\treturn nctx.NewChild()\n}\n\nfunc (s *State) toAttrs(ctx *hcl.EvalContext, opts *EvalOptions, hclAttrs hclsyntax.Attributes, scope []string) ([]*Attr, error) {\n\tattrs := make([]*Attr, 0, len(hclAttrs))\n\tfor _, hclAttr := range hclAttrs {\n\t\tvar (\n\t\t\tscope = append(scope, hclAttr.Name)\n\t\t\tnctx  = s.mayScopeContext(ctx, scope)\n\t\t)\n\t\tif path := strings.Join(scope, \".\"); s.config.lazyattrs[path] {\n\t\t\tif err := opts.Validator.ValidateAttribute(ctx, hclAttr, ExprValue(hclAttr.Expr)); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tattrs = append(attrs, LazyExprAttr(nctx, hclAttr))\n\t\t\tcontinue\n\t\t}\n\t\tvalue, diag := hclAttr.Expr.Value(nctx)\n\t\tif diag.HasErrors() {\n\t\t\treturn nil, s.typeError(diag, scope)\n\t\t}\n\t\t// Setting an attribute as null means omission.\n\t\tif value.IsNull() {\n\t\t\tcontinue\n\t\t}\n\t\tif err := opts.Validator.ValidateAttribute(ctx, hclAttr, value); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tat := &Attr{K: hclAttr.Name}\n\t\tif s.config.withPos || opts.RecordPos {\n\t\t\tat.SetRange(&hclAttr.SrcRange)\n\t\t}\n\t\tswitch t := value.Type(); {\n\t\tcase isRef(value):\n\t\t\tif !value.Type().HasAttribute(\"__ref\") {\n\t\t\t\treturn nil, fmt.Errorf(\"%s: invalid reference used in %s\", hclAttr.SrcRange, hclAttr.Name)\n\t\t\t}\n\t\t\tat.V = cty.CapsuleVal(ctyRefType, &Ref{V: value.GetAttr(\"__ref\").AsString()})\n\t\tcase (t.IsTupleType() || t.IsListType() || t.IsSetType()) && value.LengthInt() > 0:\n\t\t\tvar (\n\t\t\t\tvt     cty.Type\n\t\t\t\tvalues = make([]cty.Value, 0, value.LengthInt())\n\t\t\t)\n\t\t\tfor it := value.ElementIterator(); it.Next(); {\n\t\t\t\t_, v := it.Element()\n\t\t\t\tif isRef(v) {\n\t\t\t\t\tif !v.Type().HasAttribute(\"__ref\") {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"%s: invalid reference used in %s\", hclAttr.SrcRange, hclAttr.Name)\n\t\t\t\t\t}\n\t\t\t\t\tv = cty.CapsuleVal(ctyRefType, &Ref{V: v.GetAttr(\"__ref\").AsString()})\n\t\t\t\t}\n\t\t\t\tif vt != cty.NilType && !vt.Equals(v.Type()) {\n\t\t\t\t\treturn nil, fmt.Errorf(\"%s: mixed list types used in %q attribute\", hclAttr.SrcRange, hclAttr.Name)\n\t\t\t\t}\n\t\t\t\tvt = v.Type()\n\t\t\t\tvalues = append(values, v)\n\t\t\t}\n\t\t\tat.V = cty.ListVal(values)\n\t\tdefault:\n\t\t\tat.V = value\n\t\t}\n\t\tattrs = append(attrs, at)\n\t}\n\tsort.Slice(attrs, func(i, j int) bool {\n\t\treturn attrs[i].K < attrs[j].K\n\t})\n\treturn attrs, nil\n}\n\n// typeError improves diagnostic reporting in case of parse error.\nfunc (s *State) typeError(diag hcl.Diagnostics, scope []string) error {\n\tpath := strings.Join(scope, \".\")\n\tfor _, d := range diag {\n\t\tswitch e := d.Expression.(type) {\n\t\tcase *hclsyntax.FunctionCallExpr:\n\t\t\tif d.Summary != \"Call to unknown function\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif t, ok := s.findTypeSpec(e.Name); ok && len(t.Attributes) == 0 {\n\t\t\t\td.Detail = fmt.Sprintf(\"Type %q does not accept attributes\", t.Name)\n\t\t\t}\n\t\tcase *hclsyntax.ScopeTraversalExpr:\n\t\t\tif d.Summary != \"Unknown variable\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tswitch root := e.Traversal.RootName(); {\n\t\t\tcase root == RefData, s.config.typedblk[root] != nil:\n\t\t\t\tvar b strings.Builder\n\t\t\t\tb.WriteString(root)\n\t\t\t\tfor _, t := range e.Traversal[1:] {\n\t\t\t\t\tif v, ok := t.(hcl.TraverseAttr); ok {\n\t\t\t\t\t\tb.WriteString(\".\")\n\t\t\t\t\t\tb.WriteString(v.Name)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\td.Summary = \"Unknown data source\"\n\t\t\t\tif s.config.typedblk[root] != nil {\n\t\t\t\t\td.Summary = \"Unknown block type\"\n\t\t\t\t}\n\t\t\t\td.Detail = fmt.Sprintf(\"%s does not exist\", b.String())\n\t\t\tcase root == RefLocal:\n\t\t\t\td.Summary = \"Unknown local\"\n\t\t\tdefault:\n\t\t\t\tif t, ok := s.findTypeSpec(root); ok && len(t.Attributes) > 0 {\n\t\t\t\t\td.Detail = fmt.Sprintf(\"Type %q requires at least 1 argument\", t.Name)\n\t\t\t\t} else if n := len(scope); n > 1 && (s.config.pathVars[path] != nil || s.config.pathFuncs[path] != nil) {\n\t\t\t\t\td.Summary = strings.Replace(d.Summary, \"variable\", fmt.Sprintf(\"%s.%s\", scope[n-2], scope[n-1]), 1)\n\t\t\t\t\td.Detail = strings.Replace(d.Detail, \"variable\", scope[n-1], 1)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn diag\n}\n\n// isRef checks if the given value is a reference or a list of references.\n// Exists here for backward compatibility, use isOneRef and isRefList instead.\nfunc isRef(v cty.Value) bool {\n\tif !v.Type().IsObjectType() {\n\t\treturn false\n\t}\n\tif isOneRef(v) {\n\t\treturn true\n\t}\n\tfor it := v.ElementIterator(); it.Next(); {\n\t\tif _, v := it.Element(); isRef(v) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc isOneRef(v cty.Value) bool {\n\tt := v.Type()\n\treturn t.IsObjectType() && t.HasAttribute(\"__ref\")\n}\n\nfunc (s *State) toResource(ctx *hcl.EvalContext, opts *EvalOptions, block *hclsyntax.Block, scope []string, dec *blockDef) (spec *Resource, err error) {\n\tcloseScope, err := opts.Validator.ValidateBlock(ctx, block)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tspec = &Resource{Type: block.Type}\n\tif s.config.withPos || opts.RecordPos {\n\t\tspec.SetRange(&block.TypeRange)\n\t}\n\tswitch len(block.Labels) {\n\tcase 0:\n\tcase 1:\n\t\tspec.Name = block.Labels[0]\n\tcase 2:\n\t\tspec.Qualifier = block.Labels[0]\n\t\tspec.Name = block.Labels[1]\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"too many labels for block: %s\", block.Labels)\n\t}\n\tctx = s.mayScopeContext(ctx, scope)\n\tattrs, err := s.toAttrs(ctx, opts, block.Body.Attributes, scope)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tspec.Attrs = attrs\n\tfor _, blk := range block.Body.Blocks {\n\t\tcdec := dec.child(blk.Type)\n\t\tctx, err := setLocalVars(ctx.NewChild(), blk.Body, cdec)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tr, err := s.toResource(ctx, opts, blk, append(scope, blk.Type), cdec)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tspec.Children = append(spec.Children, r)\n\t}\n\tif err := closeScope(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn spec, nil\n}\n\n// encode the given *schemahcl.Resource into a byte slice containing an Atlas HCL\n// document representing it.\nfunc (s *State) encode(r *Resource) ([]byte, error) {\n\tvar (\n\t\tf    = hclwrite.NewFile()\n\t\tbody = f.Body()\n\t)\n\t// If the resource has a Type then it is rendered as an HCL block.\n\tif r.Type != \"\" {\n\t\tblk := body.AppendNewBlock(r.Type, labels(r))\n\t\tbody = blk.Body()\n\t}\n\tfor _, attr := range r.Attrs {\n\t\tif err := s.writeAttr(attr, body); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tfor _, res := range r.Children {\n\t\tif err := s.writeResource(res, body); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tvar buf bytes.Buffer\n\t_, err := f.WriteTo(&buf)\n\treturn buf.Bytes(), err\n}\n\nfunc (s *State) writeResource(b *Resource, body *hclwrite.Body) error {\n\t// Anonymous resources are treated as embedded blocks.\n\tif b.Type != \"\" {\n\t\tblk := body.AppendNewBlock(b.Type, labels(b))\n\t\tbody = blk.Body()\n\t}\n\tfor _, attr := range b.Attrs {\n\t\tif err := s.writeAttr(attr, body); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, b := range b.Children {\n\t\tif err := s.writeResource(b, body); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc labels(r *Resource) []string {\n\tvar l []string\n\tif r.Qualifier != \"\" {\n\t\tl = append(l, r.Qualifier)\n\t}\n\tif r.Name != \"\" {\n\t\tl = append(l, r.Name)\n\t}\n\treturn l\n}\n\nfunc (s *State) writeAttr(attr *Attr, body *hclwrite.Body) error {\n\tswitch {\n\tcase attr.IsRef():\n\t\tv, err := attr.Ref()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tts, err := hclRefTokens(v)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbody.SetAttributeRaw(attr.K, ts)\n\tcase attr.IsType():\n\t\tt, err := attr.Type()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif t.IsRef {\n\t\t\tts, err := hclRefTokens(t.T)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tbody.SetAttributeRaw(attr.K, ts)\n\t\t\tbreak\n\t\t}\n\t\tspec, ok := s.findTypeSpec(t.T)\n\t\tif !ok {\n\t\t\tv := fmt.Sprintf(\"sql(%q)\", t.T)\n\t\t\tbody.SetAttributeRaw(attr.K, hclRawTokens(v))\n\t\t\tbreak\n\t\t}\n\t\tst, err := hclType(spec, t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tbody.SetAttributeRaw(attr.K, hclRawTokens(st))\n\tcase attr.IsRawExpr():\n\t\tv, err := attr.RawExpr()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// TODO(rotemtam): the func name should be decided on contextual basis.\n\t\tfnc := fmt.Sprintf(\"sql(%q)\", v.X)\n\t\tbody.SetAttributeRaw(attr.K, hclRawTokens(fnc))\n\tcase attr.V.Type().IsListType():\n\t\t// Skip scanning nil slices ([]T(nil)) by default. Users that\n\t\t// want to print empty lists, should use make([]T, 0) instead.\n\t\tif attr.V.LengthInt() == 0 {\n\t\t\treturn nil\n\t\t}\n\t\ttokens := make([]hclwrite.Tokens, 0, attr.V.LengthInt())\n\t\tfor _, v := range attr.V.AsValueSlice() {\n\t\t\tif !v.Type().IsCapsuleType() {\n\t\t\t\ttokens = append(tokens, hclwrite.TokensForValue(v))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tswitch ev := v.EncapsulatedValue().(type) {\n\t\t\tcase *Ref:\n\t\t\t\tts, err := hclRefTokens(ev.V)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttokens = append(tokens, ts)\n\t\t\tcase *EnumString:\n\t\t\t\tswitch {\n\t\t\t\tcase ev.S != \"\" && ev.E != \"\":\n\t\t\t\t\treturn fmt.Errorf(\"enum string cannot have both a string and an expression, got: %#v\", ev)\n\t\t\t\tcase ev.S != \"\":\n\t\t\t\t\ttokens = append(tokens, hclwrite.TokensForValue(cty.StringVal(ev.S)))\n\t\t\t\tcase ev.E != \"\":\n\t\t\t\t\ttokens = append(tokens, hclwrite.Tokens{\n\t\t\t\t\t\t&hclwrite.Token{Type: hclsyntax.TokenIdent, Bytes: []byte(ev.E)},\n\t\t\t\t\t})\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"enum string must have either a string or an expression, got: %#v\", ev)\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unsupported capsule type: %v\", v.Type())\n\t\t\t}\n\t\t}\n\t\tbody.SetAttributeRaw(attr.K, hclList(tokens))\n\t// Heredoc is a special case that currently is not handled by hclwrite:\n\t// https://github.com/hashicorp/hcl/blob/main/hclwrite/generate.go#L218-L219.\n\tcase attr.V.Type() == cty.String && strings.Count(attr.V.AsString(), \"\\n\") > 1 && strings.HasPrefix(attr.V.AsString(), \"<<\"):\n\t\tv := strings.TrimLeft(attr.V.AsString(), \"<-\")\n\t\t// Heredoc begins with << (or <<-), followed by a token that\n\t\t// specifies the terminator and ends with the \\n + terminator.\n\t\tif lines := strings.Split(v, \"\\n\"); len(lines) > 2 && strings.TrimSpace(lines[0]) == strings.TrimSpace(lines[len(lines)-1]) {\n\t\t\tbody.SetAttributeRaw(attr.K, hclwrite.Tokens{\n\t\t\t\t&hclwrite.Token{\n\t\t\t\t\tType:  hclsyntax.TokenOHeredoc,\n\t\t\t\t\tBytes: escapedHeredoc(attr.V.AsString()),\n\t\t\t\t},\n\t\t\t})\n\t\t} else {\n\t\t\tbody.SetAttributeValue(attr.K, attr.V)\n\t\t}\n\tdefault:\n\t\tbody.SetAttributeValue(attr.K, attr.V)\n\t}\n\treturn nil\n}\n\n// escapedHeredoc escapes template introducer symbol when marshaling heredoc.\n// See: hcl/hclwrite#escapeQuotedStringLit for reference.\nfunc escapedHeredoc(s string) []byte {\n\tvar b bytes.Buffer\n\tfor i, r := range s {\n\t\tswitch r {\n\t\tcase '$', '%':\n\t\t\tif i < len(s)-1 && s[i+1] == '{' {\n\t\t\t\tb.WriteRune(r)\n\t\t\t}\n\t\t}\n\t\tb.WriteRune(r)\n\t}\n\treturn b.Bytes()\n}\n\nfunc (s *State) findTypeSpec(t string) (*TypeSpec, bool) {\n\tfor _, v := range s.config.types {\n\t\tif v.T == t {\n\t\t\treturn v, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\nfunc hclType(spec *TypeSpec, typ *Type) (string, error) {\n\tif spec.Format != nil {\n\t\treturn spec.Format(typ)\n\t}\n\tif len(typeFuncArgs(spec)) == 0 {\n\t\treturn spec.Name, nil\n\t}\n\targs := make([]string, 0, len(spec.Attributes))\n\tfor _, param := range typeFuncArgs(spec) {\n\t\targ, ok := findAttr(typ.Attrs, param.Name)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\targs = append(args, valueArgs(param, arg.V)...)\n\t}\n\t// If no args were chosen and the type can be described without a function.\n\tif len(args) == 0 && len(typeFuncReqArgs(spec)) == 0 {\n\t\treturn spec.Name, nil\n\t}\n\treturn fmt.Sprintf(\"%s(%s)\", spec.Name, strings.Join(args, \",\")), nil\n}\n\nfunc valueArgs(spec *TypeAttr, v cty.Value) []string {\n\tswitch {\n\tcase v.Type().IsListType(), v.Type().IsTupleType(), v.Type().IsSetType(), v.Type().IsCollectionType():\n\t\targs := make([]string, 0, v.LengthInt())\n\t\tfor _, v := range v.AsValueSlice() {\n\t\t\targs = append(args, valueArgs(spec, v)...)\n\t\t}\n\t\treturn args\n\tcase v.Type() == cty.String:\n\t\treturn []string{strconv.Quote(v.AsString())}\n\tcase v.Type() == cty.Number && spec.Kind == reflect.Int:\n\t\tiv, _ := v.AsBigFloat().Int64()\n\t\treturn []string{strconv.FormatInt(iv, 10)}\n\tcase v.Type() == cty.Number:\n\t\tfv, _ := v.AsBigFloat().Float64()\n\t\treturn []string{strconv.FormatFloat(fv, 'f', -1, 64)}\n\tcase v.Type() == cty.Bool:\n\t\treturn []string{strconv.FormatBool(v.True())}\n\t}\n\treturn nil\n}\n\nfunc findAttr(attrs []*Attr, k string) (*Attr, bool) {\n\tfor _, attr := range attrs {\n\t\tif attr.K == k {\n\t\t\treturn attr, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\nfunc hclRefTokens(v string) (t hclwrite.Tokens, err error) {\n\t// If it is a reference to a type or an enum.\n\tif !strings.HasPrefix(v, \"$\") {\n\t\treturn []*hclwrite.Token{{Type: hclsyntax.TokenIdent, Bytes: []byte(v)}}, nil\n\t}\n\tpath, err := (&Ref{V: v}).Path()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor i, p := range path {\n\t\tif i > 0 {\n\t\t\tt = append(t, &hclwrite.Token{Type: hclsyntax.TokenDot, Bytes: []byte{'.'}})\n\t\t}\n\t\tt = append(t, &hclwrite.Token{Type: hclsyntax.TokenIdent, Bytes: []byte(p.T)})\n\t\tfor _, v := range p.V {\n\t\t\tswitch {\n\t\t\tcase validIdent(v):\n\t\t\t\tt = append(t,\n\t\t\t\t\t&hclwrite.Token{Type: hclsyntax.TokenDot, Bytes: []byte{'.'}},\n\t\t\t\t\t&hclwrite.Token{Type: hclsyntax.TokenIdent, Bytes: []byte(v)},\n\t\t\t\t)\n\t\t\tdefault:\n\t\t\t\tt = append(t, &hclwrite.Token{Type: hclsyntax.TokenOBrack, Bytes: []byte{'['}})\n\t\t\t\tt = append(t, hclwrite.TokensForValue(cty.StringVal(v))...)\n\t\t\t\tt = append(t, &hclwrite.Token{Type: hclsyntax.TokenCBrack, Bytes: []byte{']'}})\n\t\t\t}\n\t\t}\n\t}\n\treturn t, nil\n}\n\nfunc hclRawTokens(s string) hclwrite.Tokens {\n\treturn hclwrite.Tokens{\n\t\t&hclwrite.Token{\n\t\t\tType:  hclsyntax.TokenIdent,\n\t\t\tBytes: []byte(s),\n\t\t},\n\t}\n}\n\nfunc hclList(items []hclwrite.Tokens) hclwrite.Tokens {\n\tt := hclwrite.Tokens{&hclwrite.Token{\n\t\tType:  hclsyntax.TokenOBrack,\n\t\tBytes: []byte(\"[\"),\n\t}}\n\tfor i, item := range items {\n\t\tif i > 0 {\n\t\t\tt = append(t, &hclwrite.Token{Type: hclsyntax.TokenComma, Bytes: []byte(\",\")})\n\t\t}\n\t\tt = append(t, item...)\n\t}\n\tt = append(t, &hclwrite.Token{\n\t\tType:  hclsyntax.TokenCBrack,\n\t\tBytes: []byte(\"]\"),\n\t})\n\treturn t\n}\n\nfunc (s *State) forEachBlocks(ctx *hcl.EvalContext, b *hclsyntax.Block) ([]*hclsyntax.Block, error) {\n\tforEach, diags := b.Body.Attributes[forEachAttr].Expr.Value(ctx)\n\tif diags.HasErrors() {\n\t\treturn nil, diags\n\t}\n\tif t := forEach.Type(); !t.IsSetType() && !t.IsObjectType() && !t.IsTupleType() {\n\t\treturn nil, fmt.Errorf(\"schemahcl: for_each does not support %s type\", t.FriendlyName())\n\t}\n\tdelete(b.Body.Attributes, forEachAttr)\n\tblocks := make([]*hclsyntax.Block, 0, forEach.LengthInt())\n\tfor it := forEach.ElementIterator(); it.Next(); {\n\t\tk, v := it.Element()\n\t\tnctx := ctx.NewChild()\n\t\tnctx.Variables = map[string]cty.Value{\n\t\t\teachRef: cty.ObjectVal(map[string]cty.Value{\n\t\t\t\t\"key\":   k,\n\t\t\t\t\"value\": v,\n\t\t\t}),\n\t\t}\n\t\tnb, err := s.copyBlock(nctx, b, []string{b.Type})\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"schemahcl: evaluate block for value %q: %w\", v, err)\n\t\t}\n\t\tblocks = append(blocks, nb)\n\t}\n\treturn blocks, nil\n}\n\nfunc (s *State) copyBlock(ctx *hcl.EvalContext, b *hclsyntax.Block, scope []string) (*hclsyntax.Block, error) {\n\tnb := &hclsyntax.Block{\n\t\tType:      b.Type,\n\t\tLabels:    b.Labels,\n\t\tTypeRange: b.TypeRange,\n\t\tBody: &hclsyntax.Body{\n\t\t\tAttributes: make(map[string]*hclsyntax.Attribute),\n\t\t\tBlocks:     make([]*hclsyntax.Block, 0, len(b.Body.Blocks)),\n\t\t},\n\t}\n\tfor k, v := range b.Body.Attributes {\n\t\tx, diags := v.Expr.Value(s.mayScopeContext(ctx, append(scope, k)))\n\t\tif diags.HasErrors() {\n\t\t\treturn nil, diags\n\t\t}\n\t\tnv := *v\n\t\tnv.Expr = &hclsyntax.LiteralValueExpr{Val: x}\n\t\tnb.Body.Attributes[k] = &nv\n\t}\n\tfor _, v := range b.Body.Blocks {\n\t\tnv, err := s.copyBlock(ctx, v, append(scope, v.Type))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tnb.Body.Blocks = append(nb.Body.Blocks, nv)\n\t}\n\treturn nb, nil\n}\n\n// Eval implements the Evaluator interface.\nfunc (f EvalFunc) Eval(p *hclparse.Parser, i any, input map[string]cty.Value) error {\n\treturn f(p, i, input)\n}\n\n// typeFuncSpec returns the HCL function for defining the type in the spec.\nfunc typeFuncSpec(typeSpec *TypeSpec) function.Function {\n\tspec := &function.Spec{\n\t\tType: function.StaticReturnType(ctyTypeSpec),\n\t}\n\tfor _, arg := range typeFuncArgs(typeSpec) {\n\t\tif arg.Kind == reflect.Slice || !arg.Required {\n\t\t\tspec.VarParam = &function.Parameter{\n\t\t\t\tName: \"args\",\n\t\t\t\tType: cty.DynamicPseudoType,\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tp := function.Parameter{\n\t\t\tName:      arg.Name,\n\t\t\tAllowNull: !arg.Required,\n\t\t}\n\t\tswitch arg.Kind {\n\t\tcase reflect.String:\n\t\t\tp.Type = cty.String\n\t\tcase reflect.Int, reflect.Float32, reflect.Int64:\n\t\t\tp.Type = cty.Number\n\t\tcase reflect.Bool:\n\t\t\tp.Type = cty.Bool\n\t\t}\n\t\tspec.Params = append(spec.Params, p)\n\t}\n\tspec.Impl = typeFuncSpecImpl(spec, typeSpec)\n\treturn function.New(spec)\n}\n\n// typeFuncSpecImpl returns the function implementation for the HCL function spec.\nfunc typeFuncSpecImpl(_ *function.Spec, typeSpec *TypeSpec) function.ImplFunc {\n\treturn func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\tt := &Type{\n\t\t\tT: typeSpec.T,\n\t\t}\n\t\tif len(args) > len(typeSpec.Attributes) && typeSpec.Attributes[len(typeSpec.Attributes)-1].Kind != reflect.Slice {\n\t\t\treturn cty.NilVal, fmt.Errorf(\"too many arguments for type definition %q\", typeSpec.Name)\n\t\t}\n\t\t// TypeRegistry enforces that:\n\t\t// 1. Required attrs come before optionals\n\t\t// 2. Slice attrs can only be last\n\t\tfor _, attr := range typeFuncArgs(typeSpec) {\n\t\t\t// If the attribute is a slice, read all remaining args into a list value.\n\t\t\tif attr.Kind == reflect.Slice {\n\t\t\t\tt.Attrs = append(t.Attrs, &Attr{K: attr.Name, V: cty.ListVal(args)})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif len(args) == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tt.Attrs = append(t.Attrs, &Attr{K: attr.Name, V: args[0]})\n\t\t\targs = args[1:]\n\t\t}\n\t\treturn cty.CapsuleVal(ctyTypeSpec, t), nil\n\t}\n}\n\n// typeFuncArgs returns the type attributes that are configured via arguments to the\n// type definition, for example precision and scale in a decimal definition, i.e `decimal(10,2)`.\nfunc typeFuncArgs(spec *TypeSpec) []*TypeAttr {\n\tvar args []*TypeAttr\n\tfor _, attr := range spec.Attributes {\n\t\t// TODO(rotemtam): this should be defined on the TypeSpec.\n\t\tif attr.Name == \"unsigned\" {\n\t\t\tcontinue\n\t\t}\n\t\targs = append(args, attr)\n\t}\n\treturn args\n}\n\n// typeFuncReqArgs returns the required type attributes that are configured via arguments.\n// for instance, in MySQL a field may be defined as both `int` and `int(10)`, in this case\n// it is not a required parameter.\nfunc typeFuncReqArgs(spec *TypeSpec) []*TypeAttr {\n\tvar args []*TypeAttr\n\tfor _, arg := range typeFuncArgs(spec) {\n\t\tif arg.Required {\n\t\t\targs = append(args, arg)\n\t\t}\n\t}\n\treturn args\n}\n\n// UseTraversal determines if the given attribute use the given traversal.\nfunc UseTraversal(x hclsyntax.Expression, tr hcl.Traversal) bool {\n\tswitch x := x.(type) {\n\tcase nil:\n\t\treturn false\n\tcase *hclsyntax.TemplateWrapExpr:\n\t\treturn UseTraversal(x.Wrapped, tr)\n\tcase *hclsyntax.TemplateJoinExpr:\n\t\treturn UseTraversal(x.Tuple, tr)\n\tcase *hclsyntax.TemplateExpr:\n\t\tif slices.ContainsFunc(x.Parts, func(p hclsyntax.Expression) bool {\n\t\t\treturn UseTraversal(p, tr)\n\t\t}) {\n\t\t\treturn true\n\t\t}\n\tcase *hclsyntax.ConditionalExpr:\n\t\tfor _, x1 := range []hclsyntax.Expression{x.Condition, x.TrueResult, x.FalseResult} {\n\t\t\tif UseTraversal(x1, tr) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\tcase *hclsyntax.FunctionCallExpr:\n\t\tif slices.ContainsFunc(x.Args, func(a hclsyntax.Expression) bool {\n\t\t\treturn UseTraversal(a, tr)\n\t\t}) {\n\t\t\treturn true\n\t\t}\n\tcase *hclsyntax.ScopeTraversalExpr:\n\t\tif len(x.Traversal) != len(tr) {\n\t\t\treturn false\n\t\t}\n\t\tif len(x.Traversal) == 0 {\n\t\t\treturn true\n\t\t}\n\t\tr1, ok1 := x.Traversal[0].(hcl.TraverseRoot)\n\t\tr2, ok2 := tr[0].(hcl.TraverseRoot)\n\t\tif !ok1 || !ok2 || r1.Name != r2.Name {\n\t\t\treturn false\n\t\t}\n\t\tfor i := 1; i < len(x.Traversal); i++ {\n\t\t\tt1, ok1 := x.Traversal[i].(hcl.TraverseAttr)\n\t\t\tt2, ok2 := tr[i].(hcl.TraverseAttr)\n\t\t\tif !ok1 || !ok2 || t1.Name != t2.Name {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\tcase *hclsyntax.RelativeTraversalExpr:\n\t\treturn UseTraversal(x.Source, tr)\n\tcase *hclsyntax.BinaryOpExpr:\n\t\treturn UseTraversal(x.LHS, tr) || UseTraversal(x.RHS, tr)\n\tcase *hclsyntax.UnaryOpExpr:\n\t\treturn UseTraversal(x.Val, tr)\n\tcase *hclsyntax.TupleConsExpr:\n\t\tfor _, e := range x.Exprs {\n\t\t\tif UseTraversal(e, tr) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\tcase *hclsyntax.ObjectConsExpr:\n\t\tfor _, item := range x.Items {\n\t\t\tif UseTraversal(item.KeyExpr, tr) || UseTraversal(item.ValueExpr, tr) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "schemahcl/schemahcl_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/hashicorp/hcl/v2/hclsyntax\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\nfunc TestAttributes(t *testing.T) {\n\tf := `i  = 1\nb  = true\ns  = \"hello, world\"\nsl = [\"hello\", \"world\"]\nbl = [true, false]\nhd = <<-EOT\n  hello\n  world\nEOT\nvars = {\n  a = \"a\"\n}\n`\n\tvar test struct {\n\t\tInt        int                  `spec:\"i\"`\n\t\tBool       bool                 `spec:\"b\"`\n\t\tStr        string               `spec:\"s\"`\n\t\tStringList []string             `spec:\"sl\"`\n\t\tBoolList   []bool               `spec:\"bl\"`\n\t\tHeredoc    string               `spec:\"hd\"`\n\t\tVars       map[string]cty.Value `spec:\"vars\"`\n\t}\n\terr := New().EvalBytes([]byte(f), &test, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, 1, test.Int)\n\trequire.EqualValues(t, true, test.Bool)\n\trequire.EqualValues(t, \"hello, world\", test.Str)\n\trequire.EqualValues(t, []string{\"hello\", \"world\"}, test.StringList)\n\trequire.EqualValues(t, []bool{true, false}, test.BoolList)\n\trequire.EqualValues(t, \"hello\\nworld\\n\", test.Heredoc)\n\trequire.EqualValues(t, \"a\", test.Vars[\"a\"].AsString())\n\t// Heredoc needs to be explicitly formatted this way.\n\ttest.Heredoc = \"<<-EOT\\n  hello\\n  world\\nEOT\"\n\tmarshal, err := Marshal(&test)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, f, string(marshal))\n\n\tvar v struct {\n\t\tNullV string  `spec:\"null_v\"`\n\t\tNullP *string `spec:\"null_p\"`\n\t}\n\terr = New().EvalBytes([]byte(`\nnull_v = null\nnull_p = null\n`), &v, nil)\n\trequire.NoError(t, err)\n\trequire.Empty(t, v.NullV)\n\trequire.Nil(t, v.NullP)\n}\n\nfunc TestResource(t *testing.T) {\n\tf := `endpoint \"/hello\" {\n  description = \"the hello handler\"\n  timeout_ms  = 100\n  handler {\n    active = true\n    addr   = \":8080\"\n    tag {\n      name  = \"name\"\n      value = \"value\"\n    }\n  }\n}\n`\n\ttype (\n\t\tHandler struct {\n\t\t\tActive bool   `spec:\"active\"`\n\t\t\tAddr   string `spec:\"addr\"`\n\t\t\tTag    struct {\n\t\t\t\tName  string `spec:\"name\"`\n\t\t\t\tValue string `spec:\"value\"`\n\t\t\t} `spec:\"tag\"`\n\t\t}\n\t\tEndpoint struct {\n\t\t\tName        string   `spec:\",name\"`\n\t\t\tDescription string   `spec:\"description\"`\n\t\t\tTimeoutMs   int      `spec:\"timeout_ms\"`\n\t\t\tHandler     *Handler `spec:\"handler\"`\n\t\t}\n\t\tFile struct {\n\t\t\tEndpoints []*Endpoint `spec:\"endpoint\"`\n\t\t}\n\t)\n\tvar test File\n\terr := New().EvalBytes([]byte(f), &test, nil)\n\trequire.NoError(t, err)\n\trequire.Len(t, test.Endpoints, 1)\n\texpected := &Endpoint{\n\t\tName:        \"/hello\",\n\t\tDescription: \"the hello handler\",\n\t\tTimeoutMs:   100,\n\t\tHandler: &Handler{\n\t\t\tActive: true,\n\t\t\tAddr:   \":8080\",\n\t\t\tTag: struct {\n\t\t\t\tName  string `spec:\"name\"`\n\t\t\t\tValue string `spec:\"value\"`\n\t\t\t}{Name: \"name\", Value: \"value\"},\n\t\t},\n\t}\n\trequire.EqualValues(t, expected, test.Endpoints[0])\n\tbuf, err := Marshal(&test)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, f, string(buf))\n}\n\nfunc TestInvalidRefs(t *testing.T) {\n\tvar doc struct {\n\t\tTables []struct {\n\t\t\tName string `spec:\",name\"`\n\t\t\tRefs []*Ref `spec:\"ref\"`\n\t\t}\n\t}\n\terr := New().EvalBytes([]byte(`\ntable \"bar\" {\n  refs = [table]\n}\n`), &doc, nil)\n\trequire.EqualError(t, err, \":3,3-17: invalid reference used in refs\")\n}\n\nfunc ExampleUnmarshal() {\n\tf := `\nshow \"seinfeld\" {\n\tday = SUN\n\twriter \"jerry\" {\n\t\tfull_name = \"Jerry Seinfeld\"\t\n\t}\n\twriter \"larry\" {\n\t\tfull_name = \"Larry David\"\t\n\t}\n}`\n\n\ttype (\n\t\tWriter struct {\n\t\t\tID       string `spec:\",name\"`\n\t\t\tFullName string `spec:\"full_name\"`\n\t\t}\n\t\tShow struct {\n\t\t\tName    string    `spec:\",name\"`\n\t\t\tDay     string    `spec:\"day\"`\n\t\t\tWriters []*Writer `spec:\"writer\"`\n\t\t}\n\t)\n\tvar (\n\t\ttest struct {\n\t\t\tShows []*Show `spec:\"show\"`\n\t\t}\n\t\topts = []Option{\n\t\t\tWithScopedEnums(\"show.day\", \"SUN\", \"MON\", \"TUE\"),\n\t\t}\n\t)\n\terr := New(opts...).EvalBytes([]byte(f), &test, nil)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tseinfeld := test.Shows[0]\n\tfmt.Printf(\"the show %q at day %s has %d writers.\", seinfeld.Name, seinfeld.Day, len(seinfeld.Writers))\n\t// Output: the show \"seinfeld\" at day SUN has 2 writers.\n}\n\nfunc ExampleMarshal() {\n\ttype (\n\t\tPoint struct {\n\t\t\tID string `spec:\",name\"`\n\t\t\tX  int    `spec:\"x\"`\n\t\t\tY  int    `spec:\"y\"`\n\t\t}\n\t)\n\tvar test = struct {\n\t\tPoints []*Point `spec:\"point\"`\n\t}{\n\t\tPoints: []*Point{\n\t\t\t{ID: \"start\", X: 0, Y: 0},\n\t\t\t{ID: \"end\", X: 1, Y: 1},\n\t\t},\n\t}\n\tb, err := Marshal(&test)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tfmt.Println(string(b))\n\t// Output:\n\t// point \"start\" {\n\t//   x = 0\n\t//   y = 0\n\t// }\n\t// point \"end\" {\n\t//   x = 1\n\t//   y = 1\n\t// }\n}\n\nfunc TestIgnore(t *testing.T) {\n\tvar test struct {\n\t\tIgnoreAttr    string `spec:\"-\"`\n\t\tNotIgnoreAttr string `spec:\"not_ignore_attr\"`\n\t\tIgnoreBlock   struct {\n\t\t\tName string `spec:\",name\"`\n\t\t} `spec:\"-\"`\n\t\tNotIgnore struct {\n\t\t\tName string `spec:\",name\"`\n\t\t} `spec:\"not_ignore_block\"`\n\t}\n\ttest.IgnoreAttr, test.NotIgnoreAttr = \"ignore\", \"not ignore\"\n\ttest.IgnoreBlock.Name, test.NotIgnore.Name = \"ignore\", \"not ignore\"\n\tbuf, err := Marshal(&test)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `not_ignore_attr = \"not ignore\"\nnot_ignore_block \"not ignore\" {\n}\n`, string(buf))\n}\n\nfunc TestInterface(t *testing.T) {\n\ttype (\n\t\tAnimal interface {\n\t\t\tanimal()\n\t\t}\n\t\tParrot struct {\n\t\t\tAnimal\n\t\t\tName string `spec:\",name\"`\n\t\t\tBoss string `spec:\"boss\"`\n\t\t}\n\t\tLion struct {\n\t\t\tAnimal\n\t\t\tName   string `spec:\",name\"`\n\t\t\tFriend string `spec:\"friend\"`\n\t\t}\n\t\tZoo struct {\n\t\t\tAnimals []Animal `spec:\"\"`\n\t\t}\n\t\tCast struct {\n\t\t\tAnimal Animal `spec:\"\"`\n\t\t}\n\t)\n\tRegister(\"lion\", &Lion{})\n\tRegister(\"parrot\", &Parrot{})\n\tt.Run(\"single\", func(t *testing.T) {\n\t\tf := `\ncast \"lion_king\" {\n\tlion \"simba\" {\n\t\tfriend = \"rafiki\"\n\t}\n}\n`\n\t\tvar test struct {\n\t\t\tCast *Cast `spec:\"cast\"`\n\t\t}\n\t\terr := New().EvalBytes([]byte(f), &test, nil)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, &Cast{\n\t\t\tAnimal: &Lion{\n\t\t\t\tName:   \"simba\",\n\t\t\t\tFriend: \"rafiki\",\n\t\t\t},\n\t\t}, test.Cast)\n\t})\n\tt.Run(\"slice\", func(t *testing.T) {\n\t\tf := `\nzoo \"ramat_gan\" {\n\tlion \"simba\" {\n\t\tfriend = \"rafiki\"\n\t}\n\tparrot \"iago\" {\n\t\tboss = \"jafar\"\n\t}\n}\n`\n\t\tvar test struct {\n\t\t\tZoo *Zoo `spec:\"zoo\"`\n\t\t}\n\t\terr := New().EvalBytes([]byte(f), &test, nil)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, &Zoo{\n\t\t\tAnimals: []Animal{\n\t\t\t\t&Lion{\n\t\t\t\t\tName:   \"simba\",\n\t\t\t\t\tFriend: \"rafiki\",\n\t\t\t\t},\n\t\t\t\t&Parrot{\n\t\t\t\t\tName: \"iago\",\n\t\t\t\t\tBoss: \"jafar\",\n\t\t\t\t},\n\t\t\t},\n\t\t}, test.Zoo)\n\t})\n}\n\nfunc TestQualified(t *testing.T) {\n\ttype Person struct {\n\t\tName  string `spec:\",name\"`\n\t\tTitle string `spec:\",qualifier\"`\n\t}\n\tvar test struct {\n\t\tPerson *Person `spec:\"person\"`\n\t}\n\th := `person \"dr\" \"jekyll\" {\n}\n`\n\terr := New().EvalBytes([]byte(h), &test, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, test.Person, &Person{\n\t\tTitle: \"dr\",\n\t\tName:  \"jekyll\",\n\t})\n\tout, err := Marshal(&test)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, h, string(out))\n}\n\nfunc TestNameAttr(t *testing.T) {\n\th := `\nnamed \"block_id\" {\n  name = \"atlas\"\n}\nref = named.block_id.name\n`\n\ttype Named struct {\n\t\tName string `spec:\"name,name\"`\n\t}\n\tvar test struct {\n\t\tNamed *Named `spec:\"named\"`\n\t\tRef   string `spec:\"ref\"`\n\t}\n\terr := New().EvalBytes([]byte(h), &test, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, &Named{\n\t\tName: \"atlas\",\n\t}, test.Named)\n\trequire.EqualValues(t, \"atlas\", test.Ref)\n}\n\nfunc TestRefPatch(t *testing.T) {\n\ttype (\n\t\tFamily struct {\n\t\t\tName string `spec:\"name,name\"`\n\t\t}\n\t\tPerson struct {\n\t\t\tName   string `spec:\",name\"`\n\t\t\tFamily *Ref   `spec:\"family\"`\n\t\t}\n\t)\n\tRegister(\"family\", &Family{})\n\tRegister(\"person\", &Person{})\n\tvar test struct {\n\t\tFamilies []*Family `spec:\"family\"`\n\t\tPeople   []*Person `spec:\"person\"`\n\t}\n\th := `\nvariable \"family_name\" {\n  type = string\n}\n\nfamily \"default\" {\n\tname = var.family_name\n}\n\nperson \"rotem\" {\n\tfamily = family.default\n}\n`\n\terr := New().EvalBytes([]byte(h), &test, map[string]cty.Value{\n\t\t\"family_name\": cty.StringVal(\"tam\"),\n\t})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"$family.tam\", test.People[0].Family.V)\n}\n\nfunc TestMultiFile(t *testing.T) {\n\ttype Person struct {\n\t\tName   string `spec:\",name\"`\n\t\tHobby  string `spec:\"hobby\"`\n\t\tParent *Ref   `spec:\"parent\"`\n\t}\n\tvar test struct {\n\t\tPeople []*Person `spec:\"person\"`\n\t}\n\tvar (\n\t\tpaths   []string\n\t\ttestDir = \"testdata/\"\n\t)\n\tdir, err := os.ReadDir(testDir)\n\trequire.NoError(t, err)\n\tfor _, file := range dir {\n\t\tif file.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\tpaths = append(paths, filepath.Join(testDir, file.Name()))\n\t}\n\terr = New().EvalFiles(paths, &test, map[string]cty.Value{\n\t\t\"hobby\": cty.StringVal(\"coding\"),\n\t})\n\trequire.NoError(t, err)\n\trequire.Len(t, test.People, 2)\n\trequire.EqualValues(t, &Person{Name: \"rotemtam\", Hobby: \"coding\"}, test.People[0])\n\trequire.EqualValues(t, &Person{\n\t\tName:   \"tzuri\",\n\t\tHobby:  \"ice-cream\",\n\t\tParent: &Ref{V: \"$person.rotemtam\"},\n\t}, test.People[1])\n}\n\nfunc TestForEachResources(t *testing.T) {\n\ttype (\n\t\tEnv struct {\n\t\t\tName string `spec:\",name\"`\n\t\t\tURL  string `spec:\"url\"`\n\t\t}\n\t)\n\tvar (\n\t\tdoc struct {\n\t\t\tEnvs []*Env `spec:\"env\"`\n\t\t}\n\t\tb = []byte(`\nvariable \"tenants\" {\n  type    = list(string)\n  default = [\"atlas\", \"ent\"]\n}\n\nvariable \"domains\" {\n  type = list(object({\n    name = string\n    port = number\n  }))\n  default = [\n    {\n      name = \"atlasgo.io\"\n      port = 443\n    },\n    {\n      name = \"entgo.io\"\n      port = 443\n    },\n  ]\n}\n\nenv \"prod\" {\n  for_each = toset(var.tenants)\n  url = \"mysql://root:pass@:3306/${each.value}\"\n}\n\nenv \"staging\" {\n  for_each = toset(var.domains)\n  url = \"${each.value.name}:${each.value.port}\"\n  driver = MYSQL\n}\n\nenv \"dev\" {\n  for_each = {\n    atlas = \"atlasgo.io\"\n    ent   = \"entgo.io\"\n  }\n  url = \"${each.value}/${each.key}\"\n}\n`)\n\t)\n\trequire.NoError(t, New(\n\t\tWithScopedEnums(\"env.driver\", \"MYSQL\", \"POSTGRES\"),\n\t\tWithDataSource(\"sql\", func(_ context.Context, ectx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, error) {\n\t\t\tattrs, diags := b.Body.JustAttributes()\n\t\t\tif diags.HasErrors() {\n\t\t\t\treturn cty.NilVal, diags\n\t\t\t}\n\t\t\tv, diags := attrs[\"query\"].Expr.Value(ectx)\n\t\t\tif diags.HasErrors() {\n\t\t\t\treturn cty.NilVal, diags\n\t\t\t}\n\t\t\treturn cty.ObjectVal(map[string]cty.Value{\"query\": v}), nil\n\t\t}),\n\t).EvalBytes(b, &doc, nil))\n\trequire.Len(t, doc.Envs, 6)\n\trequire.Equal(t, \"prod\", doc.Envs[0].Name)\n\trequire.EqualValues(t, doc.Envs[0].URL, \"mysql://root:pass@:3306/atlas\")\n\trequire.Equal(t, \"prod\", doc.Envs[1].Name)\n\trequire.EqualValues(t, doc.Envs[1].URL, \"mysql://root:pass@:3306/ent\")\n\trequire.Equal(t, \"staging\", doc.Envs[2].Name)\n\trequire.EqualValues(t, doc.Envs[2].URL, \"atlasgo.io:443\")\n\trequire.Equal(t, \"staging\", doc.Envs[3].Name)\n\trequire.EqualValues(t, doc.Envs[3].URL, \"entgo.io:443\")\n\trequire.Equal(t, \"dev\", doc.Envs[4].Name)\n\trequire.EqualValues(t, doc.Envs[4].URL, \"atlasgo.io/atlas\")\n\trequire.Equal(t, \"dev\", doc.Envs[5].Name)\n\trequire.EqualValues(t, doc.Envs[5].URL, \"entgo.io/ent\")\n\n\t// Mismatched element types.\n\terr := New().EvalBytes(b, &doc, map[string]cty.Value{\n\t\t\"domains\": cty.ListVal([]cty.Value{\n\t\t\tcty.ObjectVal(map[string]cty.Value{\n\t\t\t\t\"name\": cty.StringVal(\"a\"),\n\t\t\t\t\"port\": cty.StringVal(\"b\"),\n\t\t\t}),\n\t\t}),\n\t})\n\trequire.EqualError(t, err, `variable \"domains\": a number is required`)\n\n\tvar (\n\t\t// For-each resource depends on other resources.\n\t\tdoc1 struct {\n\t\t\tSchema []*struct {\n\t\t\t\tName string `spec:\",name\"`\n\t\t\t} `spec:\"schema\"`\n\t\t\tTable []*struct {\n\t\t\t\tName   string `spec:\"name,name\"`\n\t\t\t\tSchema *Ref   `spec:\"schema\"`\n\t\t\t} `spec:\"table\"`\n\t\t}\n\t\tb1 = []byte(`\nschema \"s1\" {}\nschema \"s2\" {}\n\ntable {\n  for_each = {\n    t1 = schema.s1\n\tt2 = schema.s2\n  }\n  name = each.key\n  schema = each.value\n}\n`)\n\t)\n\terr = New().EvalBytes(b1, &doc1, nil)\n\trequire.NoError(t, err)\n\tbuf, err := Marshal.MarshalSpec(&doc1)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `schema \"s1\" {\n}\nschema \"s2\" {\n}\ntable \"t1\" {\n  schema = schema.s1\n}\ntable \"t2\" {\n  schema = schema.s2\n}\n`, string(buf))\n\n\t// Tuple of type any.\n\tb1 = []byte(`\nschema \"s1\" {\n  comment = \"schema comment\"\n}\nschema \"s2\" {\n  # object without comment.\n}\n\ntable {\n  for_each = [schema.s1, schema.s2]\n  name = each.value.name\n  schema = each.value\n}\n`)\n\terr = New().EvalBytes(b1, &doc1, nil)\n\trequire.NoError(t, err)\n\tbuf, err = Marshal.MarshalSpec(&doc1)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `schema \"s1\" {\n}\nschema \"s2\" {\n}\ntable \"s1\" {\n  schema = schema.s1\n}\ntable \"s2\" {\n  schema = schema.s2\n}\n`, string(buf))\n}\n\nfunc TestDataLocalsRefs(t *testing.T) {\n\tvar (\n\t\topts = []Option{\n\t\t\tWithDataSource(\"sql\", func(_ context.Context, ectx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, error) {\n\t\t\t\tattrs, diags := b.Body.JustAttributes()\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\tv, diags := attrs[\"result\"].Expr.Value(ectx)\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\treturn cty.ObjectVal(map[string]cty.Value{\"output\": v}), nil\n\t\t\t}),\n\t\t\tWithDataSource(\"text\", func(_ context.Context, ectx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, error) {\n\t\t\t\tattrs, diags := b.Body.JustAttributes()\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\tv, diags := attrs[\"value\"].Expr.Value(ectx)\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\treturn cty.ObjectVal(map[string]cty.Value{\"output\": v}), nil\n\t\t\t}),\n\t\t\tWithInitBlock(\"atlas\", func(_ context.Context, ectx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, error) {\n\t\t\t\torg, diags := b.Body.Attributes[\"org\"].Expr.Value(ectx)\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\tif len(b.Body.Blocks) != 1 || b.Body.Blocks[0].Type != \"auth\" {\n\t\t\t\t\treturn cty.NilVal, errors.New(\"expected auth block\")\n\t\t\t\t}\n\t\t\t\tattrs, diags := b.Body.Blocks[0].Body.JustAttributes()\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\thost, diags := attrs[\"host\"].Expr.Value(ectx)\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\treturn cty.ObjectVal(map[string]cty.Value{\n\t\t\t\t\t\"org\": org,\n\t\t\t\t\t\"auth\": cty.ObjectVal(map[string]cty.Value{\n\t\t\t\t\t\t\"host\": host,\n\t\t\t\t\t}),\n\t\t\t\t}), nil\n\t\t\t}),\n\t\t\tWithDataSource(\"remote_dir\", func(_ context.Context, ectx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, error) {\n\t\t\t\tattrs, diags := b.Body.JustAttributes()\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\thost, diags := attrs[\"host\"].Expr.Value(ectx)\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\torg, diags := (&hclsyntax.ScopeTraversalExpr{\n\t\t\t\t\tTraversal: hcl.Traversal{\n\t\t\t\t\t\thcl.TraverseRoot{Name: \"atlas\", SrcRange: b.Range()},\n\t\t\t\t\t\thcl.TraverseAttr{Name: \"org\", SrcRange: b.Range()},\n\t\t\t\t\t},\n\t\t\t\t}).Value(ectx)\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\treturn cty.ObjectVal(map[string]cty.Value{\n\t\t\t\t\t\"url\": cty.StringVal(\"atlas://\" + path.Join(host.AsString(), org.AsString(), b.Labels[1])),\n\t\t\t\t}), nil\n\t\t\t}),\n\t\t}\n\t\tdoc struct {\n\t\t\tValues []string `spec:\"vs\"`\n\t\t}\n\t\tb = []byte(`\nvariable \"url\" {\n  type    = string\n  default = \"mysql://root:pass@:3306/atlas\"\n}\n\nlocals {\n  a = \"local-a\"\n  // locals can reference other locals.\n  b = \"local-b-ref-local-a: ${local.a}\"\n  // locals can reference data sources.\n  c = \"local-c-ref-data-a: ${data.text.a.output}\"\n  d = \"local-d\"\n  host = \"atlasgo.io\"\n  obj = {\n    k = \"obj-v\"\n  }\n}\n\ndata \"sql\" \"tenants\" {\n  url = var.url\n  // language=mysql\n  query = <<EOS\nSELECT schema_name\n  FROM information_schema.schemata\n  WHERE schema_name LIKE 'tenant_%'\nEOS\n  // fake result.\n  result = \"data-sql-tenants\"\n}\n\ndata \"text\" \"a\" {\n  // data sources can reference data sources.\n  value = \"data-text-a-ref-data-sql-tenants: ${data.sql.tenants.output}\"\n}\n\ndata \"text\" \"b\" {\n  // data sources can reference locals.\n  value = \"data-text-b-ref-local-d: ${local.d}\"\n}\n\natlas {\n  org = \"ent\"\n  auth {\n    host = local.host\n  }\n}\n\ndata \"remote_dir\" \"migrations\" {\n  host = atlas.auth.host\n}\n\ndata \"text\" \"obj\" {\n  value = local.obj.k\n}\nvs = [\n  local.a,\n  local.b,\n  local.c,\n  data.sql.tenants.output,\n  data.text.a.output,\n  data.text.b.output,\n  data.remote_dir.migrations.url,\n  data.text.obj.output,\n]\n`)\n\t)\n\trequire.NoError(t, New(opts...).EvalBytes(b, &doc, nil))\n\trequire.Equal(t, []string{\n\t\t\"local-a\",\n\t\t\"local-b-ref-local-a: local-a\",\n\t\t\"local-c-ref-data-a: data-text-a-ref-data-sql-tenants: data-sql-tenants\",\n\t\t\"data-sql-tenants\",\n\t\t\"data-text-a-ref-data-sql-tenants: data-sql-tenants\",\n\t\t\"data-text-b-ref-local-d: local-d\",\n\t\t\"atlas://atlasgo.io/ent/migrations\",\n\t\t\"obj-v\",\n\t}, doc.Values)\n\n\tb = []byte(`locals { a = local.a }`)\n\trequire.EqualError(t, New(opts...).EvalBytes(b, &doc, nil), `cyclic reference to \"local.a\"`)\n\n\tb = []byte(`\nlocals {\n  a = \"a\"\n  b = local.c\n  c = local.b\n}\n`)\n\trequire.Error(t, New(opts...).EvalBytes(b, &doc, nil), `cyclic reference to \"local.c\"`)\n\n\tb = []byte(`\ndata \"text\" \"a\" {\n  value = local.a\n}\n\nlocals {\n  a = data.text.a.output\n}\n`)\n\trequire.Error(t, New(opts...).EvalBytes(b, &doc, nil), `cyclic reference to \"data.text.a\"`)\n\n\tb = []byte(`\nout = data.unknown.a.output\n`)\n\trequire.EqualError(t, New(opts...).EvalBytes(b, &doc, nil), `:2,7-11: Unknown data source; data.unknown.a.output does not exist`)\n}\n\nfunc TestSkippedDataSrc(t *testing.T) {\n\tvar (\n\t\topts = []Option{\n\t\t\tWithDataSource(\"dynamic\", func(_ context.Context, ectx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, error) {\n\t\t\t\tattrs, diags := b.Body.JustAttributes()\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\ts, diags := attrs[\"skip\"].Expr.Value(ectx)\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\tif s.True() {\n\t\t\t\t\treturn cty.NilVal, fmt.Errorf(\"data source should be skipped, but was called with %q\", b.Labels)\n\t\t\t\t}\n\t\t\t\tv, diags := attrs[\"v\"].Expr.Value(ectx)\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\treturn cty.ObjectVal(map[string]cty.Value{\n\t\t\t\t\t\"v\": v,\n\t\t\t\t}), nil\n\t\t\t}),\n\t\t}\n\t\tv struct {\n\t\t\tV2 string `spec:\"v2\"`\n\t\t\tV3 string `spec:\"v3\"`\n\t\t}\n\t\tb = []byte(`\ndata \"dynamic\" \"skipped1\" {\n  v = \"value is irrelevant\"\n  // This attribute has no meaning, besides indicating\n  // to the test that the data source should be skipped.\n  skip = true\n}\ndata \"dynamic\" \"skipped2\" {\n  v = data.dynamic.skipped1.v\n  skip = true\n}\ndata \"dynamic\" \"evaluated1\" {\n  v = \"v1\"\n  skip = false\n}\ndata \"dynamic\" \"evaluated2\" {\n  v = \"v2\"\n  skip = false\n}\ndata \"dynamic\" \"evaluated3\" {\n  v = data.dynamic.evaluated1.v\n  skip = false\n}\n\nv2 = data.dynamic.evaluated2.v\nv3 = data.dynamic.evaluated3.v\n`)\n\t)\n\trequire.NoError(t, New(opts...).EvalBytes(b, &v, nil))\n\n\tb = []byte(`\nlocals {\n  a = data.dynamic.not_skipped1.v\n  b = local.c\n  c = \"3\"\n  d = data.dynamic.not_skipped3.v\n}\n\ndata \"dynamic\" \"not_skipped1\" {\n  v = \"v2\"\n  skip = false\n}\n\ndata \"dynamic\" \"not_skipped2\" {\n  v = \"v${local.b}\"\n  skip = false\n}\n\ndata \"dynamic\" \"not_skipped3\" {\n  v = \"v4\"\n  skip = false\n}\n\ndata \"dynamic\" \"not_skipped4\" {\n  v = \"v5\"\n  skip = false\n}\n\ndata \"dynamic\" \"skipped1\" {\n  v = local.a\n  skip = true\n}\n\ndata \"dynamic\" \"skipped2\" {\n  v = \"v\"\n  skip = true\n}\n\ndata \"dynamic\" \"skipped3\" {\n  v = data.dynamic.skipped2\n  skip = true\n}\n\ntop {\n  a = data.dynamic.not_skipped2.v // \"v3\".\n  block {\n    block {\n      a1 = local.d // \"v4\".\n      a2 = data.dynamic.not_skipped4.v // \"v5\".\n    }\n  }\n}\n\nv2 = local.a\n`)\n\tvar v1 struct {\n\t\tTop struct {\n\t\t\tA     string `spec:\"a\"`\n\t\t\tBlock struct {\n\t\t\t\tBlock struct {\n\t\t\t\t\tA1 string `spec:\"a1\"`\n\t\t\t\t\tA2 string `spec:\"a2\"`\n\t\t\t\t} `spec:\"block\"`\n\t\t\t} `spec:\"block\"`\n\t\t} `spec:\"top\"`\n\t\tV2 string `spec:\"v2\"`\n\t}\n\trequire.NoError(t, New(opts...).EvalBytes(b, &v1, nil))\n\trequire.Equal(t, \"v2\", v1.V2)\n\trequire.Equal(t, \"v3\", v1.Top.A)\n\trequire.Equal(t, \"v4\", v1.Top.Block.Block.A1)\n\trequire.Equal(t, \"v5\", v1.Top.Block.Block.A2)\n}\n\nfunc TestTypeLabelBlock(t *testing.T) {\n\tvar (\n\t\tcallD, callT int\n\t\topts         = []Option{\n\t\t\tWithTypeLabelBlock(\"driver\", \"remote\", func(_ context.Context, ectx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, error) {\n\t\t\t\tattrs, diags := b.Body.JustAttributes()\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\tv, diags := attrs[\"name\"].Expr.Value(ectx)\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\tcallT++\n\t\t\t\treturn cty.ObjectVal(map[string]cty.Value{\"url\": cty.StringVal(\"driver://\" + v.AsString())}), nil\n\t\t\t}),\n\t\t\tWithTypeLabelBlock(\"driver\", \"not_called\", func(context.Context, *hcl.EvalContext, *hclsyntax.Block) (cty.Value, error) {\n\t\t\t\tt.Fatal(\"should not be called\")\n\t\t\t\treturn cty.NilVal, nil\n\t\t\t}),\n\t\t\tWithDataSource(\"text\", func(_ context.Context, ectx *hcl.EvalContext, b *hclsyntax.Block) (cty.Value, error) {\n\t\t\t\tattrs, diags := b.Body.JustAttributes()\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\tv, diags := attrs[\"value\"].Expr.Value(ectx)\n\t\t\t\tif diags.HasErrors() {\n\t\t\t\t\treturn cty.NilVal, diags\n\t\t\t\t}\n\t\t\t\tcallD++\n\t\t\t\treturn cty.ObjectVal(map[string]cty.Value{\"output\": v}), nil\n\t\t\t}),\n\t\t}\n\t\tdoc struct {\n\t\t\tValues []string `spec:\"vs\"`\n\t\t}\n\t\tb = []byte(`\nlocals {\n  a = \"a8m\"\n}\n\ndata \"text\" \"a\" {\n  value = local.a\n}\n\ndriver \"remote\" \"myapp\" {\n  name = data.text.a.output\n}\n\nvs = [\n  driver.remote.myapp.url,\n  data.text.a.output\n]\n`)\n\t)\n\trequire.NoError(t, New(opts...).EvalBytes(b, &doc, nil))\n\trequire.Equal(t, []string{\"driver://a8m\", \"a8m\"}, doc.Values)\n\trequire.EqualValues(t, 1, callT)\n\trequire.EqualValues(t, 2, callD, \"it is up to the data source to implement caching\")\n\n\tb = []byte(`\nlocals {\n  a = \"a8m\"\n}\n\ndata \"text\" \"a\" {\n  value = local.a\n}\n\ndriver \"remote\" \"myapp\" {\n  name = data.text.a.output\n}\n`)\n\trequire.NoError(t, New(opts...).EvalBytes(b, &doc, nil))\n\trequire.Equal(t, []string{\"driver://a8m\", \"a8m\"}, doc.Values)\n\trequire.Equal(t, 1, callT)\n\trequire.Equal(t, 2, callD)\n}\n\ntype countValidator struct{ nb, na int }\n\nfunc (*countValidator) Err() error { return nil }\nfunc (c *countValidator) ValidateBody(*hcl.EvalContext, *hclsyntax.Body) (func() error, error) {\n\treturn func() error { return nil }, nil\n}\nfunc (c *countValidator) ValidateBlock(*hcl.EvalContext, *hclsyntax.Block) (func() error, error) {\n\tc.nb++\n\treturn func() error { return nil }, nil\n}\nfunc (c *countValidator) ValidateAttribute(*hcl.EvalContext, *hclsyntax.Attribute, cty.Value) error {\n\tc.na++\n\treturn nil\n}\n\nfunc TestSchemaValidator(t *testing.T) {\n\tvar (\n\t\tcv  = &countValidator{}\n\t\tdoc struct {\n\t\t\tDefaultExtension\n\t\t}\n\t)\n\terr := New(\n\t\tWithSchemaValidator(func() SchemaValidator {\n\t\t\treturn cv\n\t\t}),\n\t).EvalBytes([]byte(`\nblock \"a\" {}\nblock \"b\" {}\nblock \"c\" {}\nattr1 = \"a\"\nattr2 = \"b\"\n`), &doc, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, 3, cv.nb)\n\trequire.Equal(t, 2, cv.na)\n\n}\n\ntype errValidator struct{ err error }\n\nfunc (e *errValidator) Err() error { return e.err }\nfunc (*errValidator) ValidateBody(*hcl.EvalContext, *hclsyntax.Body) (func() error, error) {\n\treturn func() error { return nil }, nil\n}\nfunc (*errValidator) ValidateBlock(*hcl.EvalContext, *hclsyntax.Block) (func() error, error) {\n\treturn func() error { return nil }, nil\n}\nfunc (*errValidator) ValidateAttribute(*hcl.EvalContext, *hclsyntax.Attribute, cty.Value) error {\n\treturn nil\n}\n\nfunc TestSchemaValidator_Err(t *testing.T) {\n\tvar (\n\t\tev = &errValidator{\n\t\t\terr: fmt.Errorf(\"validation error\"),\n\t\t}\n\t\tdoc struct {\n\t\t\tDefaultExtension\n\t\t}\n\t)\n\terr := New(\n\t\tWithSchemaValidator(func() SchemaValidator {\n\t\t\treturn ev\n\t\t}),\n\t).EvalBytes([]byte(`\nhello = world\n`), &doc, nil)\n\trequire.EqualError(t, err, \"validation error\\n:2,9-14: Unknown variable; There is no variable named \\\"world\\\".\")\n}\n\nfunc Test_ExtraReferences(t *testing.T) {\n\ttype (\n\t\tFoo struct {\n\t\t\tName      string `spec:\",name\"`\n\t\t\tQualifier string `spec:\",qualifier\"`\n\t\t\tDefaultExtension\n\t\t}\n\t\tBlock1 struct {\n\t\t\tName string `spec:\",name\"`\n\t\t\tType string `spec:\"type\"`\n\t\t}\n\t\tBlock2 struct {\n\t\t\tName string `spec:\",name\"`\n\t\t\tRefs []*Ref `spec:\"refs\"`\n\t\t}\n\t\tExtraBar struct {\n\t\t\tBlk1 *Block1 `spec:\"blk1\"`\n\t\t\tBlk2 *Block2 `spec:\"blk2\"`\n\t\t}\n\t)\n\tvar (\n\t\tdoc struct {\n\t\t\tFoo []*Foo `spec:\"foo\"`\n\t\t}\n\t\tb = []byte(`\nfoo \"f1\" {\n\textra_bar {\n\t\tblk1 \"c1\" {\n\t\t\ttype = \"c1\"\n\t\t}\n\t\tblk2 \"p1\" {\n\t\t\trefs = [blk1.c1]\n\t\t}\n\t}\n}\n`)\n\t)\n\trequire.NoError(t, New().EvalBytes(b, &doc, nil))\n\trequire.Len(t, doc.Foo, 1)\n\n\textra, ok := doc.Foo[0].Extra.Resource(\"extra_bar\")\n\trequire.True(t, ok)\n\tvar e ExtraBar\n\trequire.NoError(t, extra.As(&e))\n\trequire.Equal(t, &ExtraBar{\n\t\tBlk1: &Block1{\n\t\t\tName: \"c1\",\n\t\t\tType: \"c1\",\n\t\t},\n\t\tBlk2: &Block2{\n\t\t\tName: \"p1\",\n\t\t\tRefs: []*Ref{{V: \"$blk1.c1\"}},\n\t\t},\n\t}, &e)\n}\n\nfunc Test_ScopeContextOverride(t *testing.T) {\n\ttype (\n\t\tFoo struct {\n\t\t\tName string `spec:\",name\"`\n\t\t}\n\t\tBar struct {\n\t\t\tName string `spec:\",name\"`\n\t\t\tAttr string `spec:\"attr\"`\n\t\t\tRef  *Ref   `spec:\"ref\"`\n\t\t}\n\t)\n\tvar (\n\t\tdoc struct {\n\t\t\tFoo []*Foo `spec:\"foo\"`\n\t\t\tBar []*Bar `spec:\"bar\"`\n\t\t}\n\t\tb = []byte(`\nfoo \"f1\" {}\nbar \"b1\" {\n\tattr = foo\n\tref  = foo.f1\n}\n`)\n\t)\n\trequire.NoError(t, New(\n\t\tWithScopedEnums(\"bar.attr\", \"foo\"), // foo is a valid value for bar.attr.\n\t).EvalBytes(b, &doc, nil))\n\trequire.Len(t, doc.Foo, 1)\n\trequire.Len(t, doc.Bar, 1)\n\trequire.Equal(t, &Bar{\n\t\tName: \"b1\",\n\t\tAttr: \"foo\",\n\t\tRef:  &Ref{V: \"$foo.f1\"},\n\t}, doc.Bar[0])\n}\n\nfunc Test_MarshalAttr(t *testing.T) {\n\tvar doc struct {\n\t\tDefaultExtension\n\t}\n\tdoc.Extra.Attrs = append(\n\t\tdoc.Extra.Attrs,\n\t\tStringEnumsAttr(\"mixed1\", &EnumString{S: \"string\"}, &EnumString{E: \"enum\"}),\n\t\tStringEnumsAttr(\"mixed2\", &EnumString{E: \"enum1\"}, &EnumString{E: \"enum2\"}),\n\t\tStringEnumsAttr(\"mixed3\", &EnumString{S: \"string1\"}, &EnumString{S: \"string1\"}),\n\t)\n\tbuf, err := Marshal(&doc)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `mixed1 = [\"string\", enum]\nmixed2 = [enum1, enum2]\nmixed3 = [\"string1\", \"string1\"]\n`, string(buf))\n}\n\nfunc Test_WithPos(t *testing.T) {\n\tvar (\n\t\tdoc struct {\n\t\t\tBar struct {\n\t\t\t\tA int `spec:\"a\"`\n\t\t\t\tDefaultExtension\n\t\t\t} `spec:\"bar\"`\n\t\t\tQux struct {\n\t\t\t\tRange *hcl.Range `spec:\",range\"`\n\t\t\t\tA     int        `spec:\"a\"`\n\t\t\t\tDefaultExtension\n\t\t\t} `spec:\"qux\"`\n\t\t\tDefaultExtension\n\t\t}\n\t\tb = []byte(`\nfoo {}\nfoo {\n  bar {\n    baz = 1\n  }\n}\nbaz = 1\nbar {\n  a = 1\n}\nqux {\n  a = 1\n}\n`)\n\t)\n\trequire.NoError(t, New(WithPos()).EvalBytes(b, &doc, nil))\n\tat, ok := doc.Extra.Attr(\"baz\")\n\trequire.True(t, ok)\n\trequire.Equal(t, 8, at.Range().Start.Line)\n\trs := doc.Extra.Resources(\"foo\")\n\trequire.Len(t, rs, 2)\n\trequire.Equal(t, 2, rs[0].Range().Start.Line)\n\trequire.Equal(t, 3, rs[1].Range().Start.Line)\n\trequire.Equal(t, 4, rs[1].Children[0].Range().Start.Line)\n\trequire.Equal(t, 5, rs[1].Children[0].Attrs[0].Range().Start.Line)\n\trequire.NotNil(t, doc.Bar.Extra.Range(), \"position should be attached to the resource\")\n\trequire.Equal(t, doc.Qux.Range.Start.Line, 12)\n\trequire.Nil(t, doc.Qux.Extra.Range(), \"position should not be attached if it was explicitly set\")\n}\n\nfunc TestExtendedBlockDef(t *testing.T) {\n\tvar (\n\t\tdoc struct {\n\t\t\tDefaultExtension\n\t\t}\n\t\tb = []byte(`\nschema \"public\" {}\ntable \"users\" {}\nmaterialized \"users_view2\" {\n  schema = schema.public\n  as = \"SELECT * FROM script_matview_inspect.users\"\n  column \"id\" {\n    null = false\n  }\n  column \"a\" {\n    null = false\n  }\n  column \"b\" {\n    null = false\n  }\n  primary_key {\n    columns = [column.id]\n  }\n  populate = true\n}\nmaterialized \"users_view\" {\n  schema = schema.public\n  to = table.users\n  as = \"SELECT * FROM script_matview_inspect.users\"\n  index \"i\" {\n    on {\n      expr = \"a\"\n    }\n  }\n  primary_key {\n    using = index.i # Not a real syntax.\n  }\n}\n`)\n\t)\n\trequire.NoError(t, New().EvalBytes(b, &doc, nil))\n}\n\nfunc TestUseTraversal(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tx    string\n\t\twant bool\n\t}{\n\t\t{\n\t\t\tx:    \"atlas.env\",\n\t\t\twant: true,\n\t\t},\n\t\t{\n\t\t\tx: \"\\\"atlas.env\\\"\",\n\t\t},\n\t\t{\n\t\t\tx:    \"\\\"${atlas.env}\\\"\",\n\t\t\twant: true,\n\t\t},\n\t\t{\n\t\t\tx:    \"contains([], atlas.env)\",\n\t\t\twant: true,\n\t\t},\n\t\t{\n\t\t\tx:    \"contains([], 1) ? atlas.env : 1\",\n\t\t\twant: true,\n\t\t},\n\t\t{\n\t\t\tx: \"contains([], 1) ? atlas.dev : 1\",\n\t\t},\n\t} {\n\t\tpr := hclparse.NewParser()\n\t\tf, diags := pr.ParseHCL([]byte(fmt.Sprintf(\"x = %s\", tt.x)), \"test.hcl\")\n\t\trequire.False(t, diags.HasErrors())\n\t\tx := f.Body.(*hclsyntax.Body).Attributes[\"x\"]\n\t\trequire.False(t, diags.HasErrors())\n\t\tgot := UseTraversal(x.Expr, hcl.Traversal{\n\t\t\thcl.TraverseRoot{Name: \"atlas\"},\n\t\t\thcl.TraverseAttr{Name: \"env\"},\n\t\t})\n\t\trequire.Equal(t, tt.want, got)\n\t}\n}\n\nfunc TestEscapeHeredoc(t *testing.T) {\n\ttype (\n\t\tAttr struct {\n\t\t\tK string `spec:\",name\"`\n\t\t\tV string `spec:\"value\"`\n\t\t}\n\t\tBlock struct {\n\t\t\tAttrs []*Attr `spec:\"attr\"`\n\t\t}\n\t\tdoc struct {\n\t\t\tBlocks []*Block `spec:\"block\"`\n\t\t}\n\t)\n\tv := &doc{\n\t\tBlocks: []*Block{\n\t\t\t{\n\t\t\t\tAttrs: []*Attr{\n\t\t\t\t\t{\n\t\t\t\t\t\tK: \"inline\",\n\t\t\t\t\t\tV: \"Hello ${username}, welcome! %{ if true }you're in%{ endif }\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tK: \"multiline\",\n\t\t\t\t\t\tV: `<<-TEXT\n Hello ${username}, welcome! %{ if true }you're in%{ endif }\n ${{text}}, ${{ text }}, ${{- text -}}\n $${{text}}, %%%{text}\nTEXT`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tbuf, err := Marshal(v)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `block {\n  attr \"inline\" {\n    value = \"Hello $${username}, welcome! %%{ if true }you're in%%{ endif }\"\n  }\n  attr \"multiline\" {\n    value = <<-TEXT\n Hello $${username}, welcome! %%{ if true }you're in%%{ endif }\n $${{text}}, $${{ text }}, $${{- text -}}\n $$${{text}}, %%%%{text}\nTEXT\n  }\n}\n`, string(buf))\n\tvar got doc\n\trequire.NoError(t, New().EvalBytes(buf, &got, nil))\n\trequire.Equal(t,\n\t\t\"Hello ${username}, welcome! %{ if true }you're in%{ endif }\",\n\t\tgot.Blocks[0].Attrs[0].V,\n\t)\n\trequire.Equal(t,\n\t\t`Hello ${username}, welcome! %{ if true }you're in%{ endif }\n${{text}}, ${{ text }}, ${{- text -}}\n$${{text}}, %%%{text}\n`,\n\t\tgot.Blocks[0].Attrs[1].V,\n\t)\n}\n"
  },
  {
    "path": "schemahcl/spec.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/hashicorp/hcl/v2/hclsyntax\"\n\t\"github.com/zclconf/go-cty/cty\"\n\t\"github.com/zclconf/go-cty/cty/gocty\"\n)\n\ntype (\n\t// Resource is a generic container for resources described in configurations.\n\tResource struct {\n\t\tName      string\n\t\tQualifier string\n\t\tType      string\n\t\tAttrs     []*Attr\n\t\tChildren  []*Resource\n\t\trang      *hcl.Range\n\t}\n\n\t// Attr is an attribute of a Resource.\n\tAttr struct {\n\t\tK    string\n\t\tV    cty.Value\n\t\trang *hcl.Range\n\t}\n\n\t// Ref implements Value and represents a reference to another Resource.\n\t// The path to a Resource under the root Resource is expressed as \"$<type>.<name>...\"\n\t// recursively. For example, a resource of type \"table\" that is named \"users\" and is a direct\n\t// child of the root Resource's address shall be \"$table.users\". A child resource of that table\n\t// of type \"column\" and named \"id\", shall be referenced as \"$table.users.$column.id\", and so on.\n\tRef struct {\n\t\tV string\n\t}\n\n\t// RawExpr implements Value and represents any raw expression.\n\tRawExpr struct {\n\t\tX string\n\t}\n\n\t// TypeSpec represents a specification for defining a Type.\n\tTypeSpec struct {\n\t\t// Name is the identifier for the type in an Atlas DDL document.\n\t\tName string\n\n\t\t// T is the database identifier for the type.\n\t\tT          string\n\t\tAttributes []*TypeAttr\n\n\t\t// RType is the reflect.Type of the schema.Type used to describe the TypeSpec.\n\t\t// This field is optional and used to determine the TypeSpec in cases where the\n\t\t// schema.Type does not have a `T` field.\n\t\tRType reflect.Type\n\n\t\t// Format is an optional formatting function.\n\t\t// If exists, it will be used instead the registry one.\n\t\tFormat func(*Type) (string, error)\n\n\t\t// FromSpec is an optional function that can be attached\n\t\t// to the type spec and allows converting the schema spec\n\t\t// type to a schema type (from document to database).\n\t\tFromSpec func(*Type) (schema.Type, error)\n\n\t\t// ToSpec is an optional function that can be attached\n\t\t// to the type spec and allows converting the schema type\n\t\t// to a schema spec type (from database to document).\n\t\tToSpec func(schema.Type) (*Type, error)\n\t}\n\n\t// TypeAttr describes an attribute of a TypeSpec, for example `varchar` fields\n\t// can have a `size` attribute.\n\tTypeAttr struct {\n\t\t// Name should be a snake_case of related the schema.Type struct field.\n\t\tName     string\n\t\tKind     reflect.Kind\n\t\tRequired bool\n\t}\n\n\t// Type represents the type of the field in a schema.\n\tType struct {\n\t\tT     string\n\t\tAttrs []*Attr\n\t\tIsRef bool\n\t\tIsRaw bool\n\t}\n)\n\n// IsRefTo indicates if the Type is a reference to specific schema type definition.\nfunc (t *Type) IsRefTo(n string) bool {\n\tif !t.IsRef {\n\t\treturn false\n\t}\n\tpath, err := (&Ref{V: t.T}).ByType(n)\n\treturn err == nil && len(path) > 0\n}\n\n// IsRef indicates if the attribute is a reference type.\nfunc (a *Attr) IsRef() bool {\n\tif !a.V.Type().IsCapsuleType() {\n\t\treturn false\n\t}\n\t_, ok := a.V.EncapsulatedValue().(*Ref)\n\treturn ok\n}\n\n// IsRawExpr indicates if the attribute is a RawExpr type.\nfunc (a *Attr) IsRawExpr() bool {\n\tif !a.V.Type().IsCapsuleType() {\n\t\treturn false\n\t}\n\t_, ok := a.V.EncapsulatedValue().(*RawExpr)\n\treturn ok\n}\n\n// IsType indicates if the attribute is a type spec.\nfunc (a *Attr) IsType() bool {\n\tif !a.V.Type().IsCapsuleType() {\n\t\treturn false\n\t}\n\t_, ok := a.V.EncapsulatedValue().(*Type)\n\treturn ok\n}\n\n// Int returns an int from the Value of the Attr. If The value is not a LiteralValue or the value\n// cannot be converted to an integer an error is returned.\nfunc (a *Attr) Int() (int, error) {\n\ti, err := a.Int64()\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\treturn int(i), nil\n}\n\n// Float64 returns a float64 from the Value of the Attr. If The value is not a LiteralValue or the value\n// cannot be converted to a float64 an error is returned.\nfunc (a *Attr) Float64() (f float64, err error) {\n\tif err = gocty.FromCtyValue(a.V, &f); err != nil {\n\t\treturn 0, err\n\t}\n\treturn f, nil\n}\n\n// BigFloat returns a big.Float from the Value of the Attr. If The value is not a LiteralValue or the value\n// cannot be converted to a big.Float an error is returned.\nfunc (a *Attr) BigFloat() (*big.Float, error) {\n\tvar f big.Float\n\tif err := gocty.FromCtyValue(a.V, &f); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &f, nil\n}\n\n// Int64 returns an int64 from the Value of the Attr. If The value is not a LiteralValue or the value\n// cannot be converted to an integer an error is returned.\nfunc (a *Attr) Int64() (i int64, err error) {\n\tif err = gocty.FromCtyValue(a.V, &i); err != nil {\n\t\treturn 0, err\n\t}\n\treturn i, nil\n}\n\n// String returns a string from the Value of the Attr. If The value is not a LiteralValue\n// an error is returned. String values are expected to be quoted. If the value is not\n// properly quoted an error is returned.\nfunc (a *Attr) String() (s string, err error) {\n\tif err = gocty.FromCtyValue(a.V, &s); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn s, nil\n}\n\n// Bool returns a boolean from the Value of the Attr. If The value is not a LiteralValue or the value\n// cannot be converted to a boolean an error is returned.\nfunc (a *Attr) Bool() (b bool, err error) {\n\tif err = gocty.FromCtyValue(a.V, &b); err != nil {\n\t\treturn false, err\n\t}\n\treturn b, nil\n}\n\n// Ref extracts the reference from the Value of the Attr.\nfunc (a *Attr) Ref() (string, error) {\n\tref, ok := a.V.EncapsulatedValue().(*Ref)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"schema: cannot read attribute %q as ref\", a.K)\n\t}\n\treturn ref.V, nil\n}\n\n// Type extracts the Type from the Attr.\nfunc (a *Attr) Type() (*Type, error) {\n\tt, ok := a.V.EncapsulatedValue().(*Type)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"schema: cannot read attribute %q as type\", a.K)\n\t}\n\treturn t, nil\n}\n\n// RawExpr extracts the RawExpr from the Attr.\nfunc (a *Attr) RawExpr() (*RawExpr, error) {\n\tif !a.IsRawExpr() {\n\t\treturn nil, fmt.Errorf(\"schema: cannot read attribute %q as raw expression\", a.K)\n\t}\n\treturn a.V.EncapsulatedValue().(*RawExpr), nil\n}\n\n// Refs returns a slice of references.\nfunc (a *Attr) Refs() ([]*Ref, error) {\n\trefs := make([]*Ref, 0, len(a.V.AsValueSlice()))\n\tfor _, v := range a.V.AsValueSlice() {\n\t\tref, ok := v.EncapsulatedValue().(*Ref)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"schema: cannot read attribute %q as ref\", a.K)\n\t\t}\n\t\trefs = append(refs, ref)\n\t}\n\treturn refs, nil\n}\n\n// Strings returns a slice of strings from the Value of the Attr. If The value is not a ListValue or its\n// values cannot be converted to strings an error is returned.\nfunc (a *Attr) Strings() (vs []string, err error) {\n\tif a.V.Type().IsTupleType() {\n\t\tfor _, v := range a.V.AsValueSlice() {\n\t\t\tvar s string\n\t\t\tif err = gocty.FromCtyValue(v, &s); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tvs = append(vs, s)\n\t\t}\n\t\treturn vs, nil\n\t}\n\tif err = gocty.FromCtyValue(a.V, &vs); err != nil {\n\t\treturn nil, err\n\t}\n\treturn vs, nil\n}\n\n// PathIndex represents an index in a reference path.\ntype PathIndex struct {\n\tT string   // type\n\tV []string // identifiers\n}\n\n// Check if the path index is valid.\nfunc (p *PathIndex) Check() error {\n\tif p.T == \"\" || len(p.V) == 0 {\n\t\treturn fmt.Errorf(\"schemahcl: missing type or identifier %v\", p)\n\t}\n\tfor _, v := range p.V {\n\t\tif v == \"\" {\n\t\t\treturn fmt.Errorf(\"schemahcl: empty identifier %v\", p)\n\t\t}\n\t}\n\treturn nil\n}\n\n// ByType returns the path index for the given type.\nfunc (r *Ref) ByType(name string) ([]string, error) {\n\tif r == nil {\n\t\treturn nil, fmt.Errorf(\"schemahcl: type %q was not found in nil reference\", name)\n\t}\n\tpath, err := r.Path()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar vs []string\n\tfor _, p := range path {\n\t\tswitch {\n\t\tcase p.T != name:\n\t\tcase vs != nil:\n\t\t\treturn nil, fmt.Errorf(\"schemahcl: multiple %q found in reference\", name)\n\t\tdefault:\n\t\t\tif err := p.Check(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tvs = p.V\n\t\t}\n\t}\n\tif vs == nil {\n\t\treturn nil, fmt.Errorf(\"schemahcl: missing %q in reference\", name)\n\t}\n\treturn vs, nil\n}\n\n// Path returns a parsed path including block types and their identifiers.\nfunc (r *Ref) Path() (path []PathIndex, err error) {\n\tfor i := 0; i < len(r.V); i++ {\n\t\tvar part PathIndex\n\t\tswitch idx := strings.IndexAny(r.V[i:], \".[\"); {\n\t\tcase r.V[i] != '$':\n\t\t\treturn nil, fmt.Errorf(\"schemahcl: missing type in reference %q\", r.V[i:])\n\t\tcase idx == -1:\n\t\t\treturn nil, fmt.Errorf(\"schemahcl: missing identifier in reference %q\", r.V[i:])\n\t\tdefault:\n\t\t\tpart.T = r.V[i+1 : i+idx]\n\t\t\ti += idx\n\t\t}\n\tIdent:\n\t\tfor i < len(r.V) {\n\t\t\tswitch {\n\t\t\t// End of identifier before a type.\n\t\t\tcase strings.HasPrefix(r.V[i:], \".$\"):\n\t\t\t\tbreak Ident\n\t\t\t// Scan identifier.\n\t\t\tcase r.V[i] == '.':\n\t\t\t\tv := r.V[i+1:]\n\t\t\t\tif idx := strings.IndexAny(v, \".[\"); idx != -1 {\n\t\t\t\t\tv = v[:idx]\n\t\t\t\t}\n\t\t\t\tpart.V = append(part.V, v)\n\t\t\t\ti += 1 + len(v)\n\t\t\t// Scan attribute ([\"...\"]).\n\t\t\tcase strings.HasPrefix(r.V[i:], \"[\\\"\"):\n\t\t\t\tidx := scanString(r.V[i+2:])\n\t\t\t\tif idx == -1 {\n\t\t\t\t\treturn nil, fmt.Errorf(\"schemahcl: unterminated string in reference %q\", r.V[i:])\n\t\t\t\t}\n\t\t\t\tv := r.V[i+2 : i+2+idx]\n\t\t\t\ti += 2 + idx\n\t\t\t\tif !strings.HasPrefix(r.V[i:], \"\\\"]\") {\n\t\t\t\t\treturn nil, fmt.Errorf(\"schemahcl: missing ']' in reference %q\", r.V[i:])\n\t\t\t\t}\n\t\t\t\tpart.V = append(part.V, v)\n\t\t\t\ti += 2\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"schemahcl: invalid character in reference %q\", r.V[i:])\n\t\t\t}\n\t\t}\n\t\tif err := part.Check(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpath = append(path, part)\n\t}\n\treturn\n}\n\n// BuildRef from a path.\nfunc BuildRef(path []PathIndex) *Ref {\n\tvar v string\n\tfor _, p := range path {\n\t\tswitch {\n\t\tcase len(p.V) == 1:\n\t\t\tv = addr(v, p.T, p.V[0], \"\")\n\t\tcase len(p.V) == 2:\n\t\t\tv = addr(v, p.T, p.V[1], p.V[0])\n\t\tdefault:\n\t\t\tv = addr(v, p.T, \"\", \"\")\n\t\t}\n\t}\n\treturn &Ref{V: v}\n}\n\nfunc scanString(s string) int {\n\tfor i := 0; i < len(s); i++ {\n\t\tswitch s[i] {\n\t\tcase '\\\\':\n\t\t\ti++\n\t\tcase '\"':\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// Bools returns a slice of bools from the Value of the Attr. If The value is not a ListValue or its\n// values cannot be converted to bools an error is returned.\nfunc (a *Attr) Bools() (vs []bool, err error) {\n\tif a.V.Type().IsTupleType() {\n\t\tfor _, v := range a.V.AsValueSlice() {\n\t\t\tvar b bool\n\t\t\tif err = gocty.FromCtyValue(v, &b); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tvs = append(vs, b)\n\t\t}\n\t\treturn vs, nil\n\t}\n\tif err = gocty.FromCtyValue(a.V, &vs); err != nil {\n\t\treturn nil, err\n\t}\n\treturn vs, nil\n}\n\n// SetRange sets the range of this attribute.\nfunc (a *Attr) SetRange(p *hcl.Range) {\n\ta.rang = p\n}\n\n// Range returns the attribute range on the\n// file, or nil if it is not set.\nfunc (a *Attr) Range() *hcl.Range {\n\treturn a.rang\n}\n\n// SetRange sets the range of this resource.\nfunc (r *Resource) SetRange(p *hcl.Range) {\n\tr.rang = p\n}\n\n// Range returns the resource range on the\n// file, or nil if it is not set.\nfunc (r *Resource) Range() *hcl.Range {\n\treturn r.rang\n}\n\n// Resource returns the first child Resource by its type and reports whether it was found.\nfunc (r *Resource) Resource(t string) (*Resource, bool) {\n\tif r == nil {\n\t\treturn nil, false\n\t}\n\tfor i := range r.Children {\n\t\tif r.Children[i].Type == t {\n\t\t\treturn r.Children[i], true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Resources returns all child Resources by its type.\nfunc (r *Resource) Resources(t string) []*Resource {\n\tif r == nil {\n\t\treturn nil\n\t}\n\tvar rs []*Resource\n\tfor i := range r.Children {\n\t\tif r.Children[i].Type == t {\n\t\t\trs = append(rs, r.Children[i])\n\t\t}\n\t}\n\treturn rs\n}\n\n// Attr returns the Attr by the provided name and reports whether it was found.\nfunc (r *Resource) Attr(name string) (*Attr, bool) {\n\tif at, ok := attrVal(r.Attrs, name); ok {\n\t\treturn at, true\n\t}\n\tfor _, r := range r.Children {\n\t\tif at, ok := attrVal(r.Attrs, name); ok && r.Type == \"\" {\n\t\t\treturn at, true // Match on embedded resource.\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// SetAttr sets the Attr on the Resource. If r is nil, a zero value Resource\n// is initialized. If an Attr with the same key exists, it is replaced by attr.\nfunc (r *Resource) SetAttr(attr *Attr) {\n\tr.Attrs = replaceOrAppendAttr(r.Attrs, attr)\n}\n\n// EmbedAttr is like SetAttr but appends the attribute to an embedded\n// resource, cause it to be marshaled after current blocks and attributes.\nfunc (r *Resource) EmbedAttr(attr *Attr) {\n\tr.Children = append(r.Children, &Resource{\n\t\tAttrs: []*Attr{attr},\n\t})\n}\n\n// MarshalSpec implements Marshaler.\nfunc (f MarshalerFunc) MarshalSpec(v any) ([]byte, error) {\n\treturn f(v)\n}\n\nfunc attrVal(attrs []*Attr, name string) (*Attr, bool) {\n\tfor _, attr := range attrs {\n\t\tif attr.K == name {\n\t\t\treturn attr, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\nfunc replaceOrAppendAttr(attrs []*Attr, attr *Attr) []*Attr {\n\tfor i, v := range attrs {\n\t\tif v.K == attr.K {\n\t\t\tattrs[i] = attr\n\t\t\treturn attrs\n\t\t}\n\t}\n\treturn append(attrs, attr)\n}\n\n// Attr returns a TypeAttr by name and reports if one was found.\nfunc (s *TypeSpec) Attr(name string) (*TypeAttr, bool) {\n\tfor _, ta := range s.Attributes {\n\t\tif ta.Name == name {\n\t\t\treturn ta, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\nvar _ Marshaler = MarshalerFunc(nil)\n\n// StringAttr is a helper method for constructing *schemahcl.Attr instances that contain string value.\nfunc StringAttr(k string, v string) *Attr {\n\treturn &Attr{\n\t\tK: k,\n\t\tV: cty.StringVal(v),\n\t}\n}\n\n// IntAttr is a helper method for constructing *schemahcl.Attr instances that contain int64 value.\nfunc IntAttr(k string, v int) *Attr {\n\treturn Int64Attr(k, int64(v))\n}\n\n// Int64Attr is a helper method for constructing *schemahcl.Attr instances that contain int64 value.\nfunc Int64Attr(k string, v int64) *Attr {\n\treturn &Attr{\n\t\tK: k,\n\t\tV: cty.NumberVal(new(big.Float).SetInt64(v).SetPrec(512)),\n\t}\n}\n\n// Float64Attr is a helper method for constructing *schemahcl.Attr instances that contain float64 value.\nfunc Float64Attr(k string, v float64) *Attr {\n\treturn &Attr{\n\t\tK: k,\n\t\tV: cty.NumberFloatVal(v),\n\t}\n}\n\n// BoolAttr is a helper method for constructing *schemahcl.Attr instances that contain a boolean value.\nfunc BoolAttr(k string, v bool) *Attr {\n\treturn &Attr{\n\t\tK: k,\n\t\tV: cty.BoolVal(v),\n\t}\n}\n\n// RefAttr is a helper method for constructing *schemahcl.Attr instances that contain a Ref value.\nfunc RefAttr(k string, v *Ref) *Attr {\n\treturn &Attr{\n\t\tK: k,\n\t\tV: cty.CapsuleVal(ctyRefType, v),\n\t}\n}\n\n// RefValue is a helper method for constructing a cty.Value that contains a Ref value.\nfunc RefValue(v string) cty.Value {\n\treturn cty.CapsuleVal(ctyRefType, &Ref{V: v})\n}\n\n// TypeValue is a helper method for constructing a cty.Value that contains a Type value.\nfunc TypeValue(t *Type) cty.Value {\n\treturn cty.CapsuleVal(ctyTypeSpec, t)\n}\n\n// StringsAttr is a helper method for constructing *schemahcl.Attr instances that contain list strings.\nfunc StringsAttr(k string, vs ...string) *Attr {\n\tvv := make([]cty.Value, len(vs))\n\tfor i, v := range vs {\n\t\tvv[i] = cty.StringVal(v)\n\t}\n\treturn &Attr{\n\t\tK: k,\n\t\tV: cty.ListVal(vv),\n\t}\n}\n\n// RefsAttr is a helper method for constructing *schemahcl.Attr instances that contain list references.\nfunc RefsAttr(k string, refs ...*Ref) *Attr {\n\tvv := make([]cty.Value, len(refs))\n\tfor i, v := range refs {\n\t\tvv[i] = cty.CapsuleVal(ctyRefType, v)\n\t}\n\treturn &Attr{\n\t\tK: k,\n\t\tV: cty.ListVal(vv),\n\t}\n}\n\n// RawAttr is a helper method for constructing *schemahcl.Attr instances that contain RawExpr value.\nfunc RawAttr(k string, x string) *Attr {\n\treturn &Attr{\n\t\tK: k,\n\t\tV: RawExprValue(&RawExpr{X: x}),\n\t}\n}\n\n// RawExprValue is a helper method for constructing a cty.Value that capsules a raw expression.\nfunc RawExprValue(x *RawExpr) cty.Value {\n\treturn cty.CapsuleVal(ctyRawExpr, x)\n}\n\n// ctyEnumString is a capsule type for EnumString.\nvar ctyEnumString = cty.Capsule(\"enum_string\", reflect.TypeOf(EnumString{}))\n\n// EnumString is a helper type that represents\n// either an enum or a string value.\ntype EnumString struct {\n\tE, S string // Enum or string value.\n}\n\n// StringEnumsAttr is a helper method for constructing *schemahcl.Attr instances\n// that contain list of elements that their values can be either enum or string.\nfunc StringEnumsAttr(k string, elems ...*EnumString) *Attr {\n\tvv := make([]cty.Value, len(elems))\n\tfor i, e := range elems {\n\t\tvv[i] = cty.CapsuleVal(ctyEnumString, e)\n\t}\n\treturn &Attr{\n\t\tK: k,\n\t\tV: cty.ListVal(vv),\n\t}\n}\n\n// TypeExpr is a capsule type for HCL expressions. It allows passing to the\n// type-checker expressions that should not be evaluated, but only validated.\nvar TypeExpr = cty.Capsule(\"expr\", reflect.TypeOf((*hclsyntax.Expression)(nil)).Elem())\n\n// ExprValue returns a cty.Value that encapsulates the given HCL expression.\nfunc ExprValue(x hclsyntax.Expression) cty.Value {\n\treturn cty.CapsuleVal(TypeExpr, &x)\n}\n\n// ExprFunc for lazy attribute evaluation.\ntype ExprFunc func(map[string]cty.Value) (cty.Value, error)\n\n// ctyAttr is a capsule type for hcl.Attribute.\nvar ctyExprFunc = cty.Capsule(\"expr_func\", reflect.TypeOf(new(ExprFunc)).Elem())\n\n// LazyExprAttr is a helper method for constructing *schemahcl.Attr instance for the expression function.\nfunc LazyExprAttr(ctx *hcl.EvalContext, at *hclsyntax.Attribute) *Attr {\n\tvar (\n\t\tr = at.Range()\n\t\tx = ExprFunc(func(vars map[string]cty.Value) (cty.Value, error) {\n\t\t\tif len(vars) > 0 {\n\t\t\t\tctx = ctx.NewChild()\n\t\t\t\tctx.Variables = vars\n\t\t\t}\n\t\t\tv, diags := at.Expr.Value(ctx)\n\t\t\tif diags.HasErrors() {\n\t\t\t\treturn cty.NilVal, diags\n\t\t\t}\n\t\t\treturn v, nil\n\t\t})\n\t)\n\treturn &Attr{\n\t\tK:    at.Name,\n\t\trang: &r,\n\t\tV:    cty.CapsuleVal(ctyExprFunc, &x),\n\t}\n}\n\n// LazyExpr returns a lazy expression function stored in the attribute value.\nfunc (a *Attr) LazyExpr() (ExprFunc, error) {\n\tif !a.V.Type().IsCapsuleType() {\n\t\treturn nil, fmt.Errorf(\"attribute %s is not a capsule type\", a.K)\n\t}\n\tx, ok := a.V.EncapsulatedValue().(*ExprFunc)\n\tif !ok || x == nil {\n\t\treturn nil, fmt.Errorf(\"attribute %s is not an expression function\", a.K)\n\t}\n\treturn *x, nil\n}\n\n// RangeAsPos builds a schema position from the give HCL range.\nfunc RangeAsPos(r *hcl.Range) *schema.Pos {\n\treturn &schema.Pos{\n\t\tFilename: r.Filename,\n\t\tStart:    r.Start,\n\t\tEnd:      r.End,\n\t}\n}\n\n// AppendPos appends the range to the attributes.\nfunc AppendPos(attrs *[]schema.Attr, r *hcl.Range) {\n\tif r != nil {\n\t\tschema.ReplaceOrAppend(attrs, RangeAsPos(r))\n\t}\n}\n"
  },
  {
    "path": "schemahcl/spec_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRef_Path(t *testing.T) {\n\ttests := []struct {\n\t\tref      string\n\t\twantPath []PathIndex\n\t\twantErr  bool\n\t}{\n\t\t{\n\t\t\tref:     \"invalid\",\n\t\t\twantErr: true, // invalid path\n\t\t},\n\t\t{\n\t\t\tref:     \"$schema\",\n\t\t\twantErr: true, // missing identifier\n\t\t},\n\t\t{\n\t\t\tref:     \"$schema.\",\n\t\t\twantErr: true, // empty identifier\n\t\t},\n\t\t{\n\t\t\tref:     `$schema[\"\"].foo`,\n\t\t\twantErr: true, // empty identifier\n\t\t},\n\t\t{\n\t\t\tref:     \"$.main\",\n\t\t\twantErr: true, // empty type\n\t\t},\n\t\t{\n\t\t\tref: \"$schema.main\",\n\t\t\twantPath: []PathIndex{\n\t\t\t\t{T: \"schema\", V: []string{\"main\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tref: \"$schema.main.$table.users\",\n\t\t\twantPath: []PathIndex{\n\t\t\t\t{T: \"schema\", V: []string{\"main\"}},\n\t\t\t\t{T: \"table\", V: []string{\"users\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tref: \"$schema.main.$table.global.users\",\n\t\t\twantPath: []PathIndex{\n\t\t\t\t{T: \"schema\", V: []string{\"main\"}},\n\t\t\t\t{T: \"table\", V: []string{\"global\", \"users\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tref: \"$schema.main.$table.global.users.$column.name\",\n\t\t\twantPath: []PathIndex{\n\t\t\t\t{T: \"schema\", V: []string{\"main\"}},\n\t\t\t\t{T: \"table\", V: []string{\"global\", \"users\"}},\n\t\t\t\t{T: \"column\", V: []string{\"name\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tref: `$account[\"ariga.cloud\"][\"a8m.dev\"]`,\n\t\t\twantPath: []PathIndex{\n\t\t\t\t{T: \"account\", V: []string{\"ariga.cloud\", \"a8m.dev\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tref: `$foo.bar[\"baz\"].qux.$bar.baz[\"qux\"].$baz.qux`,\n\t\t\twantPath: []PathIndex{\n\t\t\t\t{T: \"foo\", V: []string{\"bar\", \"baz\", \"qux\"}},\n\t\t\t\t{T: \"bar\", V: []string{\"baz\", \"qux\"}},\n\t\t\t\t{T: \"baz\", V: []string{\"qux\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tref: `$foo[\"bar\"][\"baz\"][\"qux\"].$bar[\"baz\"][\"qux\"].$baz[\"qux\"]`,\n\t\t\twantPath: []PathIndex{\n\t\t\t\t{T: \"foo\", V: []string{\"bar\", \"baz\", \"qux\"}},\n\t\t\t\t{T: \"bar\", V: []string{\"baz\", \"qux\"}},\n\t\t\t\t{T: \"baz\", V: []string{\"qux\"}},\n\t\t\t},\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tr := &Ref{V: tt.ref}\n\t\t\tpath, err := r.Path()\n\t\t\trequire.Equal(t, tt.wantErr, err != nil, err)\n\t\t\trequire.Equal(t, tt.wantPath, path)\n\t\t})\n\t}\n}\n\nfunc TestBuildRef(t *testing.T) {\n\ttests := []struct {\n\t\tpath    []PathIndex\n\t\twantRef string\n\t}{\n\t\t{\n\t\t\tpath:    []PathIndex{{T: \"schema\"}, {T: \"table\"}},\n\t\t\twantRef: `$schema.$table`,\n\t\t},\n\t\t{\n\t\t\tpath:    []PathIndex{{T: \"schema\", V: []string{\"main\"}}},\n\t\t\twantRef: `$schema.main`,\n\t\t},\n\t\t{\n\t\t\tpath: []PathIndex{\n\t\t\t\t{T: \"schema\", V: []string{\"main\"}},\n\t\t\t\t{T: \"table\", V: []string{\"users\"}},\n\t\t\t},\n\t\t\twantRef: `$schema.main.$table.users`,\n\t\t},\n\t\t{\n\t\t\tpath: []PathIndex{\n\t\t\t\t{T: \"schema\", V: []string{\"main\"}},\n\t\t\t\t{T: \"table\", V: []string{\"main\", \"users\"}},\n\t\t\t},\n\t\t\twantRef: `$schema.main.$table.main.users`,\n\t\t},\n\t\t{\n\t\t\tpath: []PathIndex{\n\t\t\t\t{T: \"schema\", V: []string{\"main\"}},\n\t\t\t\t{T: \"table\", V: []string{\"main\", \"foo.bar\"}},\n\t\t\t},\n\t\t\twantRef: `$schema.main.$table.main[\"foo.bar\"]`,\n\t\t},\n\t\t{\n\t\t\tpath: []PathIndex{\n\t\t\t\t{T: \"schema\", V: []string{\"schema-name\"}},\n\t\t\t\t{T: \"table\", V: []string{\"other.schema\", \"foo.bar\"}},\n\t\t\t\t{T: \"column\", V: []string{\"column-name\"}},\n\t\t\t},\n\t\t\twantRef: `$schema.schema-name.$table[\"other.schema\"][\"foo.bar\"].$column.column-name`,\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tref := BuildRef(tt.path)\n\t\t\trequire.Equal(t, tt.wantRef, ref.V)\n\t\t})\n\t}\n}\n\nfunc TestRangeAsPos(t *testing.T) {\n\tp := RangeAsPos(&hcl.Range{\n\t\tFilename: \"schema.pg.hcl\",\n\t})\n\trequire.Equal(t, &schema.Pos{Filename: \"schema.pg.hcl\"}, p)\n\n\tp = RangeAsPos(&hcl.Range{\n\t\tFilename: \"schema.pg.hcl\",\n\t\tStart:    hcl.Pos{Byte: 10},\n\t\tEnd:      hcl.Pos{Byte: 20},\n\t})\n\trequire.Equal(t, &schema.Pos{Filename: \"schema.pg.hcl\", Start: hcl.Pos{Byte: 10}, End: hcl.Pos{Byte: 20}}, p)\n}\n"
  },
  {
    "path": "schemahcl/stdlib.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/bmatcuk/doublestar\"\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/hashicorp/hcl/v2/ext/tryfunc\"\n\tctyyaml \"github.com/zclconf/go-cty-yaml\"\n\t\"github.com/zclconf/go-cty/cty\"\n\t\"github.com/zclconf/go-cty/cty/convert\"\n\t\"github.com/zclconf/go-cty/cty/function\"\n\t\"github.com/zclconf/go-cty/cty/function/stdlib\"\n\t\"github.com/zclconf/go-cty/cty/json\"\n\t\"gopkg.in/yaml.v3\"\n)\n\nfunc stdTypes(ctx *hcl.EvalContext) *hcl.EvalContext {\n\tctx = ctx.NewChild()\n\tctx.Variables = map[string]cty.Value{\n\t\t\"string\": cty.CapsuleVal(ctyNilType, &cty.String),\n\t\t\"bool\":   cty.CapsuleVal(ctyNilType, &cty.Bool),\n\t\t\"number\": cty.CapsuleVal(ctyNilType, &cty.Number),\n\t\t// Exists for backwards compatibility.\n\t\t\"int\": cty.CapsuleVal(ctyNilType, &cty.Number),\n\t}\n\tctx.Functions = map[string]function.Function{\n\t\t\"list\": function.New(&function.Spec{\n\t\t\tParams: []function.Parameter{\n\t\t\t\t{Name: \"elem_type\", Type: ctyNilType},\n\t\t\t},\n\t\t\tType: function.StaticReturnType(ctyNilType),\n\t\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\t\targT := args[0].EncapsulatedValue().(*cty.Type)\n\t\t\t\tlistT := cty.List(*argT)\n\t\t\t\treturn cty.CapsuleVal(ctyNilType, &listT), nil\n\t\t\t},\n\t\t}),\n\t\t\"set\": function.New(&function.Spec{\n\t\t\tParams: []function.Parameter{\n\t\t\t\t{Name: \"elem_type\", Type: ctyNilType},\n\t\t\t},\n\t\t\tType: function.StaticReturnType(ctyNilType),\n\t\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\t\targT := args[0].EncapsulatedValue().(*cty.Type)\n\t\t\t\tsetT := cty.Set(*argT)\n\t\t\t\treturn cty.CapsuleVal(ctyNilType, &setT), nil\n\t\t\t},\n\t\t}),\n\t\t\"map\": function.New(&function.Spec{\n\t\t\tParams: []function.Parameter{\n\t\t\t\t{Name: \"elem_type\", Type: ctyNilType},\n\t\t\t},\n\t\t\tType: function.StaticReturnType(ctyNilType),\n\t\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\t\targT := args[0].EncapsulatedValue().(*cty.Type)\n\t\t\t\tmapT := cty.Map(*argT)\n\t\t\t\treturn cty.CapsuleVal(ctyNilType, &mapT), nil\n\t\t\t},\n\t\t}),\n\t\t\"tuple\": function.New(&function.Spec{\n\t\t\tParams: []function.Parameter{\n\t\t\t\t{Name: \"elem_type\", Type: cty.List(ctyNilType)},\n\t\t\t},\n\t\t\tType: function.StaticReturnType(ctyNilType),\n\t\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\t\targV := args[0]\n\t\t\t\targsT := make([]cty.Type, 0, argV.LengthInt())\n\t\t\t\tfor it := argV.ElementIterator(); it.Next(); {\n\t\t\t\t\t_, ev := it.Element()\n\t\t\t\t\targsT = append(argsT, *ev.EncapsulatedValue().(*cty.Type))\n\t\t\t\t}\n\t\t\t\ttupleT := cty.Tuple(argsT)\n\t\t\t\treturn cty.CapsuleVal(ctyNilType, &tupleT), nil\n\t\t\t},\n\t\t}),\n\t\t\"object\": function.New(&function.Spec{\n\t\t\tParams: []function.Parameter{\n\t\t\t\t{Name: \"attr_type\", Type: cty.Map(ctyNilType)},\n\t\t\t},\n\t\t\tType: function.StaticReturnType(ctyNilType),\n\t\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\t\targV := args[0]\n\t\t\t\targsT := make(map[string]cty.Type)\n\t\t\t\tfor it := argV.ElementIterator(); it.Next(); {\n\t\t\t\t\tnameV, typeV := it.Element()\n\t\t\t\t\tname := nameV.AsString()\n\t\t\t\t\targsT[name] = *typeV.EncapsulatedValue().(*cty.Type)\n\t\t\t\t}\n\t\t\t\tobjT := cty.Object(argsT)\n\t\t\t\treturn cty.CapsuleVal(ctyNilType, &objT), nil\n\t\t\t},\n\t\t}),\n\t}\n\treturn ctx\n}\n\n// standard functions exist in schemahcl language.\nfunc stdFuncs() map[string]function.Function {\n\treturn map[string]function.Function{\n\t\t\"abs\":             stdlib.AbsoluteFunc,\n\t\t\"alltrue\":         allTrueFunc,\n\t\t\"can\":             tryfunc.CanFunc,\n\t\t\"ceil\":            stdlib.CeilFunc,\n\t\t\"chomp\":           stdlib.ChompFunc,\n\t\t\"chunklist\":       stdlib.ChunklistFunc,\n\t\t\"coalescelist\":    stdlib.CoalesceListFunc,\n\t\t\"compact\":         stdlib.CompactFunc,\n\t\t\"concat\":          stdlib.ConcatFunc,\n\t\t\"contains\":        stdlib.ContainsFunc,\n\t\t\"csvdecode\":       stdlib.CSVDecodeFunc,\n\t\t\"distinct\":        stdlib.DistinctFunc,\n\t\t\"element\":         stdlib.ElementFunc,\n\t\t\"empty\":           emptyFunc,\n\t\t\"endswith\":        endsWithFunc,\n\t\t\"flatten\":         stdlib.FlattenFunc,\n\t\t\"floor\":           stdlib.FloorFunc,\n\t\t\"format\":          stdlib.FormatFunc,\n\t\t\"formatdate\":      stdlib.FormatDateFunc,\n\t\t\"formatlist\":      stdlib.FormatListFunc,\n\t\t\"indent\":          stdlib.IndentFunc,\n\t\t\"index\":           stdlib.IndexFunc,\n\t\t\"join\":            stdlib.JoinFunc,\n\t\t\"jsondecode\":      stdlib.JSONDecodeFunc,\n\t\t\"jsonencode\":      stdlib.JSONEncodeFunc,\n\t\t\"yamldecode\":      ctyyaml.YAMLDecodeFunc,\n\t\t\"yamlencode\":      ctyyaml.YAMLEncodeFunc,\n\t\t\"yamlmerge\":       yamlMergeFunc,\n\t\t\"keys\":            stdlib.KeysFunc,\n\t\t\"length\":          stdlib.LengthFunc,\n\t\t\"log\":             stdlib.LogFunc,\n\t\t\"lower\":           stdlib.LowerFunc,\n\t\t\"max\":             stdlib.MaxFunc,\n\t\t\"merge\":           stdlib.MergeFunc,\n\t\t\"min\":             stdlib.MinFunc,\n\t\t\"parseint\":        stdlib.ParseIntFunc,\n\t\t\"pow\":             stdlib.PowFunc,\n\t\t\"print\":           printFunc,\n\t\t\"range\":           stdlib.RangeFunc,\n\t\t\"regex\":           stdlib.RegexFunc,\n\t\t\"regexall\":        stdlib.RegexAllFunc,\n\t\t\"regexpescape\":    regexpEscape,\n\t\t\"regexreplace\":    stdlib.RegexReplaceFunc,\n\t\t\"replace\":         stdlib.ReplaceFunc,\n\t\t\"reverse\":         stdlib.ReverseListFunc,\n\t\t\"setintersection\": stdlib.SetIntersectionFunc,\n\t\t\"setproduct\":      stdlib.SetProductFunc,\n\t\t\"setsubtract\":     stdlib.SetSubtractFunc,\n\t\t\"setunion\":        stdlib.SetUnionFunc,\n\t\t\"signum\":          stdlib.SignumFunc,\n\t\t\"slice\":           stdlib.SliceFunc,\n\t\t\"sort\":            stdlib.SortFunc,\n\t\t\"split\":           stdlib.SplitFunc,\n\t\t\"startswith\":      startsWithFunc,\n\t\t\"strrev\":          stdlib.ReverseFunc,\n\t\t\"substr\":          stdlib.SubstrFunc,\n\t\t\"timeadd\":         stdlib.TimeAddFunc,\n\t\t\"title\":           stdlib.TitleFunc,\n\t\t\"tobool\":          makeToFunc(cty.Bool),\n\t\t\"tolist\":          makeToFunc(cty.List(cty.DynamicPseudoType)),\n\t\t\"tonumber\":        makeToFunc(cty.Number),\n\t\t\"toset\":           makeToFunc(cty.Set(cty.DynamicPseudoType)),\n\t\t\"tostring\":        makeToFunc(cty.String),\n\t\t\"trim\":            stdlib.TrimFunc,\n\t\t\"trimprefix\":      stdlib.TrimPrefixFunc,\n\t\t\"trimspace\":       stdlib.TrimSpaceFunc,\n\t\t\"trimsuffix\":      stdlib.TrimSuffixFunc,\n\t\t\"try\":             tryfunc.TryFunc,\n\t\t\"upper\":           stdlib.UpperFunc,\n\t\t\"urlescape\":       urlEscapeFunc,\n\t\t\"urluserinfo\":     urlUserinfoFunc,\n\t\t\"urlqueryset\":     urlQuerySetFunc,\n\t\t\"urlsetpath\":      urlSetPathFunc,\n\t\t\"values\":          stdlib.ValuesFunc,\n\t\t\"zipmap\":          stdlib.ZipmapFunc,\n\t\t// A patch from the past. Should be moved\n\t\t// to specific scopes in the future.\n\t\t\"sql\": rawExprFunc,\n\t}\n}\n\n// makeToFunc constructs a \"to...\" function, like \"tostring\", which converts\n// its argument to a specific type or type kind. Code was copied from:\n// github.com/hashicorp/terraform/blob/master/internal/lang/funcs/conversion.go\nfunc makeToFunc(wantTy cty.Type) function.Function {\n\treturn function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"v\",\n\t\t\t\t// We use DynamicPseudoType rather than wantTy here so that\n\t\t\t\t// all values will pass through the function API verbatim and\n\t\t\t\t// we can handle the conversion logic within the Type and\n\t\t\t\t// Impl functions. This allows us to customize the error\n\t\t\t\t// messages to be more appropriate for an explicit type\n\t\t\t\t// conversion, whereas the cty function system produces\n\t\t\t\t// messages aimed at _implicit_ type conversions.\n\t\t\t\tType:             cty.DynamicPseudoType,\n\t\t\t\tAllowNull:        true,\n\t\t\t\tAllowMarked:      true,\n\t\t\t\tAllowDynamicType: true,\n\t\t\t},\n\t\t},\n\t\tType: func(args []cty.Value) (cty.Type, error) {\n\t\t\tgotTy := args[0].Type()\n\t\t\tif gotTy.Equals(wantTy) {\n\t\t\t\treturn wantTy, nil\n\t\t\t}\n\t\t\tconv := convert.GetConversionUnsafe(args[0].Type(), wantTy)\n\t\t\tif conv == nil {\n\t\t\t\t// We'll use some specialized errors for some trickier cases,\n\t\t\t\t// but most we can handle in a simple way.\n\t\t\t\tswitch {\n\t\t\t\tcase gotTy.IsTupleType() && wantTy.IsTupleType():\n\t\t\t\t\treturn cty.NilType, function.NewArgErrorf(0, \"incompatible tuple type for conversion: %s\", convert.MismatchMessage(gotTy, wantTy))\n\t\t\t\tcase gotTy.IsObjectType() && wantTy.IsObjectType():\n\t\t\t\t\treturn cty.NilType, function.NewArgErrorf(0, \"incompatible object type for conversion: %s\", convert.MismatchMessage(gotTy, wantTy))\n\t\t\t\tdefault:\n\t\t\t\t\treturn cty.NilType, function.NewArgErrorf(0, \"cannot convert %s to %s\", gotTy.FriendlyName(), wantTy.FriendlyNameForConstraint())\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If a conversion is available then everything is fine.\n\t\t\treturn wantTy, nil\n\t\t},\n\t\tImpl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {\n\t\t\t// We didn't set \"AllowUnknown\" on our argument, so it is guaranteed\n\t\t\t// to be known here but may still be null.\n\t\t\tret, err := convert.Convert(args[0], retType)\n\t\t\tif err != nil {\n\t\t\t\tval, _ := args[0].UnmarkDeep()\n\t\t\t\t// Because we used GetConversionUnsafe above, conversion can\n\t\t\t\t// still potentially fail in here. For example, if the user\n\t\t\t\t// asks to convert the string \"a\" to bool then we'll\n\t\t\t\t// optimistically permit it during type checking but fail here\n\t\t\t\t// once we note that the value isn't either \"true\" or \"false\".\n\t\t\t\tgotTy := val.Type()\n\t\t\t\tswitch {\n\t\t\t\tcase gotTy == cty.String && wantTy == cty.Bool:\n\t\t\t\t\twhat := \"string\"\n\t\t\t\t\tif !val.IsNull() {\n\t\t\t\t\t\twhat = strconv.Quote(val.AsString())\n\t\t\t\t\t}\n\t\t\t\t\treturn cty.NilVal, function.NewArgErrorf(0, `cannot convert %s to bool; only the strings \"true\" or \"false\" are allowed`, what)\n\t\t\t\tcase gotTy == cty.String && wantTy == cty.Number:\n\t\t\t\t\twhat := \"string\"\n\t\t\t\t\tif !val.IsNull() {\n\t\t\t\t\t\twhat = strconv.Quote(val.AsString())\n\t\t\t\t\t}\n\t\t\t\t\treturn cty.NilVal, function.NewArgErrorf(0, `cannot convert %s to number; given string must be a decimal representation of a number`, what)\n\t\t\t\tdefault:\n\t\t\t\t\treturn cty.NilVal, function.NewArgErrorf(0, \"cannot convert %s to %s\", gotTy.FriendlyName(), wantTy.FriendlyNameForConstraint())\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn ret, nil\n\t\t},\n\t})\n}\n\nvar (\n\t// rawExprFunc is a stub function for raw expressions.\n\trawExprFunc = function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{Name: \"def\", Type: cty.String, AllowNull: false},\n\t\t},\n\t\tType:        function.StaticReturnType(ctyRawExpr),\n\t\tDescription: \"sql is a stub function for raw expressions.\",\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tx := args[0].AsString()\n\t\t\tif len(x) == 0 {\n\t\t\t\treturn cty.NilVal, errors.New(\"empty expression\")\n\t\t\t}\n\t\t\tt := &RawExpr{X: x}\n\t\t\treturn cty.CapsuleVal(ctyRawExpr, t), nil\n\t\t},\n\t})\n\n\turlQuerySetFunc = function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"url\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"key\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"value\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t},\n\t\tType:        function.StaticReturnType(cty.String),\n\t\tDescription: \"urlqueryset sets the query parameter for the URL.\",\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tu, err := url.Parse(args[0].AsString())\n\t\t\tif err != nil {\n\t\t\t\treturn cty.NilVal, err\n\t\t\t}\n\t\t\tq := u.Query()\n\t\t\tq.Set(args[1].AsString(), args[2].AsString())\n\t\t\tu.RawQuery = q.Encode()\n\t\t\treturn cty.StringVal(u.String()), nil\n\t\t},\n\t})\n\n\turlUserinfoFunc = function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"url\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"user\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t},\n\t\tVarParam: &function.Parameter{\n\t\t\tName:      \"pass\",\n\t\t\tType:      cty.String,\n\t\t\tAllowNull: true,\n\t\t},\n\t\tType:        function.StaticReturnType(cty.String),\n\t\tDescription: \"urluserinfo sets the user for the URL.\",\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tu, err := url.Parse(args[0].AsString())\n\t\t\tif err != nil {\n\t\t\t\treturn cty.NilVal, err\n\t\t\t}\n\t\t\tuser := args[1].AsString()\n\t\t\tif len(args) > 2 && !args[2].IsNull() {\n\t\t\t\tu.User = url.UserPassword(user, args[2].AsString())\n\t\t\t} else {\n\t\t\t\tu.User = url.User(user)\n\t\t\t}\n\t\t\treturn cty.StringVal(u.String()), nil\n\t\t},\n\t})\n\n\turlSetPathFunc = function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"url\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"path\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t},\n\t\tType:        function.StaticReturnType(cty.String),\n\t\tDescription: \"urlsetpath sets the path for the URL.\",\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tu, err := url.Parse(args[0].AsString())\n\t\t\tif err != nil {\n\t\t\t\treturn cty.NilVal, err\n\t\t\t}\n\t\t\tu.Path = args[1].AsString()\n\t\t\treturn cty.StringVal(u.String()), nil\n\t\t},\n\t})\n\n\turlEscapeFunc = function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"string\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t},\n\t\tType:        function.StaticReturnType(cty.String),\n\t\tDescription: \"urlescape escapes the string so it can be safely placed inside a URL query.\",\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tu := url.QueryEscape(args[0].AsString())\n\t\t\treturn cty.StringVal(u), nil\n\t\t},\n\t})\n\n\tprintFunc = function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"print\",\n\t\t\t\tType: cty.DynamicPseudoType,\n\t\t\t},\n\t\t},\n\t\tType: func(args []cty.Value) (cty.Type, error) {\n\t\t\treturn args[0].Type(), nil\n\t\t},\n\t\tDescription: \"print prints the value to stdout, and returns the value.\",\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tswitch args[0].Type() {\n\t\t\tcase cty.String:\n\t\t\t\tfmt.Println(args[0].AsString())\n\t\t\tcase cty.Number:\n\t\t\t\tfmt.Println(args[0].AsBigFloat().String())\n\t\t\tcase cty.Bool:\n\t\t\t\tfmt.Println(args[0].True())\n\t\t\tdefault:\n\t\t\t\tif b, err := json.Marshal(args[0], args[0].Type()); err != nil {\n\t\t\t\t\tfmt.Println(args[0].GoString())\n\t\t\t\t} else {\n\t\t\t\t\tfmt.Println(string(b))\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn args[0], nil\n\t\t},\n\t})\n\n\tstartsWithFunc = function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"s\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"prefix\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t},\n\t\tType: function.StaticReturnType(cty.Bool),\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tif s1, s2 := args[0].AsString(), args[1].AsString(); strings.HasPrefix(s1, s2) {\n\t\t\t\treturn cty.True, nil\n\t\t\t}\n\t\t\treturn cty.False, nil\n\t\t},\n\t})\n\n\tendsWithFunc = function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"s\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"suffix\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t},\n\t\tType: function.StaticReturnType(cty.Bool),\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tif s1, s2 := args[0].AsString(), args[1].AsString(); strings.HasSuffix(s1, s2) {\n\t\t\t\treturn cty.True, nil\n\t\t\t}\n\t\t\treturn cty.False, nil\n\t\t},\n\t})\n\n\tregexpEscape = function.New(&function.Spec{\n\t\tDescription: `Return a string that escapes all regular expression metacharacters in the provided text.`,\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"str\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t},\n\t\tType: function.StaticReturnType(cty.String),\n\t\tImpl: func(args []cty.Value, _ cty.Type) (ret cty.Value, err error) {\n\t\t\treturn cty.StringVal(regexp.QuoteMeta(args[0].AsString())), nil\n\t\t},\n\t})\n\n\trefineNonNull = func(b *cty.RefinementBuilder) *cty.RefinementBuilder {\n\t\treturn b.NotNull()\n\t}\n\n\temptyFunc = function.New(&function.Spec{\n\t\tDescription: `Returns a boolean indicating whether the given collection is empty.`,\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName:             \"collection\",\n\t\t\t\tType:             cty.DynamicPseudoType,\n\t\t\t\tAllowDynamicType: true,\n\t\t\t\tAllowUnknown:     true,\n\t\t\t\tAllowMarked:      true,\n\t\t\t},\n\t\t},\n\t\tType: func(args []cty.Value) (ret cty.Type, err error) {\n\t\t\tcollTy := args[0].Type()\n\t\t\tif !(collTy.IsTupleType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType) {\n\t\t\t\treturn cty.NilType, fmt.Errorf(\"collection must be a list, a map or a tuple\")\n\t\t\t}\n\t\t\treturn cty.Bool, nil\n\t\t},\n\t\tRefineResult: refineNonNull,\n\t\tImpl: func(args []cty.Value, _ cty.Type) (ret cty.Value, err error) {\n\t\t\treturn args[0].Length().Equals(cty.NumberIntVal(0)), nil\n\t\t},\n\t})\n\n\tallTrueFunc = function.New(&function.Spec{\n\t\tDescription: `Returns a boolean indicating whether all elements in the given collection are true.`,\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName:             \"collection\",\n\t\t\t\tType:             cty.DynamicPseudoType,\n\t\t\t\tAllowDynamicType: true,\n\t\t\t\tAllowUnknown:     true,\n\t\t\t\tAllowMarked:      true,\n\t\t\t},\n\t\t},\n\t\tType: func(args []cty.Value) (ret cty.Type, err error) {\n\t\t\tcollTy := args[0].Type()\n\t\t\tif !(collTy.IsTupleType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType) {\n\t\t\t\treturn cty.NilType, fmt.Errorf(\"collection must be a list, a map or a tuple\")\n\t\t\t}\n\t\t\treturn cty.Bool, nil\n\t\t},\n\t\tRefineResult: refineNonNull,\n\t\tImpl: func(args []cty.Value, _ cty.Type) (ret cty.Value, err error) {\n\t\t\tfor _, v := range args[0].AsValueSlice() {\n\t\t\t\tif v.Type() != cty.Bool || !v.True() {\n\t\t\t\t\treturn cty.False, nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn cty.True, nil\n\t\t},\n\t})\n\n\tyamlMergeFunc = function.New(&function.Spec{\n\t\tDescription: \"Merges multiple YAML documents into one.\",\n\t\tVarParam: &function.Parameter{\n\t\t\tName:      \"values\",\n\t\t\tType:      cty.String,\n\t\t\tAllowNull: true,\n\t\t},\n\t\tType:         function.StaticReturnType(cty.String),\n\t\tRefineResult: refineNonNull,\n\t\tImpl: func(args []cty.Value, _ cty.Type) (ret cty.Value, err error) {\n\t\t\tswitch len(args) {\n\t\t\tcase 0:\n\t\t\t\treturn cty.NullVal(cty.String), nil\n\t\t\tcase 1:\n\t\t\t\tif args[0].IsNull() {\n\t\t\t\t\treturn cty.NullVal(cty.String), nil\n\t\t\t\t}\n\t\t\t\tif args[0].Type() != cty.String {\n\t\t\t\t\treturn cty.NilVal, function.NewArgErrorf(0, \"yamlmerge: expected string value, got %s\", args[0].Type())\n\t\t\t\t}\n\t\t\t\treturn args[0], nil\n\t\t\tdefault:\n\t\t\t\tdst := make(map[string]any)\n\t\t\t\tfor i, v := range args {\n\t\t\t\t\tif v.IsNull() {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif v.Type() != cty.String {\n\t\t\t\t\t\treturn cty.NilVal, function.NewArgErrorf(i, \"yamlmerge: expected string value, got %s\", v.Type())\n\t\t\t\t\t}\n\t\t\t\t\tvar obj map[string]any\n\t\t\t\t\tif err = yaml.Unmarshal([]byte(v.AsString()), &obj); err != nil {\n\t\t\t\t\t\treturn cty.NilVal, function.NewArgErrorf(i, \"yamlmerge: failed to unmarshal yaml: %s\", err)\n\t\t\t\t\t}\n\t\t\t\t\tif err = deepMerge(dst, obj); err != nil {\n\t\t\t\t\t\treturn cty.NilVal, function.NewArgErrorf(i, \"yamlmerge: failed to merge yaml: %s\", err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tout, err := yaml.Marshal(dst)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn cty.NilVal, fmt.Errorf(\"yamlmerge: failed to marshal yaml: %s\", err)\n\t\t\t\t}\n\t\t\t\treturn cty.StringVal(string(out)), nil\n\t\t\t}\n\t\t},\n\t})\n)\n\n// MakeFileFunc returns a function that reads a file\n// from the given base directory.\nfunc MakeFileFunc(base string) function.Function {\n\treturn function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"path\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t},\n\t\tType: function.StaticReturnType(cty.String),\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tif !filepath.IsAbs(base) {\n\t\t\t\treturn cty.NilVal, fmt.Errorf(\"base directory must be an absolute path. got: %s\", base)\n\t\t\t}\n\t\t\tpath := args[0].AsString()\n\t\t\tif !filepath.IsAbs(path) {\n\t\t\t\tpath = filepath.Clean(filepath.Join(base, path))\n\t\t\t}\n\t\t\tsrc, err := os.ReadFile(path)\n\t\t\tif err != nil {\n\t\t\t\treturn cty.NilVal, err\n\t\t\t}\n\t\t\treturn cty.StringVal(string(src)), nil\n\t\t},\n\t})\n}\n\n// MakeGlobFunc returns a function that returns the names of all files\n// matching pattern or nil if there is no matching file\n// Deprecated: use fileset function instead.\nfunc MakeGlobFunc(base string) function.Function {\n\treturn function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName: \"pattern\",\n\t\t\t\tType: cty.String,\n\t\t\t},\n\t\t},\n\t\tType: function.StaticReturnType(cty.List(cty.String)),\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tif !filepath.IsAbs(base) {\n\t\t\t\treturn cty.NilVal, fmt.Errorf(\"base directory must be an absolute path. got: %s\", base)\n\t\t\t}\n\t\t\tpath := args[0].AsString()\n\t\t\tif !filepath.IsAbs(path) {\n\t\t\t\tpath = filepath.Clean(filepath.Join(base, path))\n\t\t\t}\n\t\t\tmatches, err := filepath.Glob(path)\n\t\t\tswitch {\n\t\t\tcase err != nil:\n\t\t\t\treturn cty.NilVal, err\n\t\t\tcase len(matches) == 0:\n\t\t\t\treturn cty.ListValEmpty(cty.String), nil\n\t\t\tdefault:\n\t\t\t\tvals := make([]cty.Value, len(matches))\n\t\t\t\tfor i, match := range matches {\n\t\t\t\t\tvals[i] = cty.StringVal(match)\n\t\t\t\t}\n\t\t\t\treturn cty.ListVal(vals), nil\n\t\t\t}\n\t\t},\n\t})\n}\n\n// MakeFileSetFunc returns a function that returns the names of all files\n// matching pattern or nil if there is no matching file\nfunc MakeFileSetFunc(base string) function.Function {\n\treturn function.New(&function.Spec{\n\t\tParams: []function.Parameter{\n\t\t\t{\n\t\t\t\tName:        \"pattern\",\n\t\t\t\tType:        cty.String,\n\t\t\t\tDescription: \"A file glob pattern to match against files in the base directory.\",\n\t\t\t},\n\t\t},\n\t\tType:        function.StaticReturnType(cty.List(cty.String)),\n\t\tDescription: \"fileset returns a list of file paths matching the given glob pattern in the base directory.\",\n\t\tImpl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {\n\t\t\tif !filepath.IsAbs(base) {\n\t\t\t\treturn cty.NilVal, fmt.Errorf(\"base directory must be an absolute path. got: %s\", base)\n\t\t\t}\n\t\t\tpath := args[0].AsString()\n\t\t\tif !filepath.IsAbs(path) {\n\t\t\t\tpath = filepath.Clean(filepath.Join(base, path))\n\t\t\t}\n\t\t\tmatches, err := doublestar.Glob(path)\n\t\t\tswitch {\n\t\t\tcase err != nil:\n\t\t\t\treturn cty.NilVal, err\n\t\t\tcase len(matches) == 0:\n\t\t\t\treturn cty.ListValEmpty(cty.String), nil\n\t\t\tdefault:\n\t\t\t\tvals := make([]cty.Value, len(matches))\n\t\t\t\tfor i, match := range matches {\n\t\t\t\t\tvals[i] = cty.StringVal(match)\n\t\t\t\t}\n\t\t\t\treturn cty.ListVal(vals), nil\n\t\t\t}\n\t\t},\n\t})\n}\n\nfunc deepMerge(dst, src map[string]any) error {\n\tfor k, v := range src {\n\t\tswitch val := v.(type) {\n\t\tcase map[string]any:\n\t\t\tif _, ok := dst[k]; !ok {\n\t\t\t\tdst[k] = make(map[string]any)\n\t\t\t}\n\t\t\td, ok := dst[k].(map[string]any)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"key %s is defined in both src and dst, but has a different type\", k)\n\t\t\t}\n\t\t\tif err := deepMerge(d, val); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase []any:\n\t\t\tif _, ok := dst[k]; !ok {\n\t\t\t\tdst[k] = []any{}\n\t\t\t}\n\t\t\td, ok := dst[k].([]any)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"key %s is defined in both src and dst, but has a different type\", k)\n\t\t\t}\n\t\t\tdst[k] = append(d, val...)\n\t\tdefault:\n\t\t\tdst[k] = val\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "schemahcl/stdlib_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\nfunc TestURLSetPathFunc(t *testing.T) {\n\ttests := []struct {\n\t\tURL  cty.Value\n\t\tPath cty.Value\n\t\tWant cty.Value\n\t}{\n\t\t{\n\t\t\tcty.StringVal(\"mysql://root:pass@mysql:3306\"),\n\t\t\tcty.StringVal(\"\"),\n\t\t\tcty.StringVal(\"mysql://root:pass@mysql:3306\"),\n\t\t},\n\t\t{\n\t\t\tcty.StringVal(\"mysql://root:pass@mysql:3306?parseTime=true\"),\n\t\t\tcty.StringVal(\"my-tenant\"),\n\t\t\tcty.StringVal(\"mysql://root:pass@mysql:3306/my-tenant?parseTime=true\"),\n\t\t},\n\t\t{\n\t\t\tcty.StringVal(\"mysql://root:pass@mysql:3306/admin?parseTime=true\"),\n\t\t\tcty.StringVal(\"my-tenant\"),\n\t\t\tcty.StringVal(\"mysql://root:pass@mysql:3306/my-tenant?parseTime=true\"),\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(fmt.Sprintf(\"(%#v,%#v)\", test.URL, test.Path), func(t *testing.T) {\n\t\t\tgot, err := urlSetPathFunc.Call([]cty.Value{test.URL, test.Path})\n\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t\t}\n\t\t\tif !got.RawEquals(test.Want) {\n\t\t\t\tt.Errorf(\"wrong result\\ngot:  %#v\\nwant: %#v\", got, test.Want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestURLQuerySetFunc(t *testing.T) {\n\ttests := []struct {\n\t\tURL   cty.Value\n\t\tKey   cty.Value\n\t\tValue cty.Value\n\t\tWant  cty.Value\n\t}{\n\t\t{\n\t\t\tcty.StringVal(\"postgres://postgres:pass@0.0.0.0:5432/database?sslmode=disable&sslmode=disable\"),\n\t\t\tcty.StringVal(\"search_path\"),\n\t\t\tcty.StringVal(\"schema\"),\n\t\t\tcty.StringVal(\"postgres://postgres:pass@0.0.0.0:5432/database?search_path=schema&sslmode=disable&sslmode=disable\"),\n\t\t},\n\t\t{\n\t\t\tcty.StringVal(\"postgres://postgres:pass@0.0.0.0:5432/database?sslmode=disable&search_path=admin&sslmode=disable\"),\n\t\t\tcty.StringVal(\"search_path\"),\n\t\t\tcty.StringVal(\"schema\"),\n\t\t\tcty.StringVal(\"postgres://postgres:pass@0.0.0.0:5432/database?search_path=schema&sslmode=disable&sslmode=disable\"),\n\t\t},\n\t\t{\n\t\t\tcty.StringVal(\"postgres://postgres:pass@0.0.0.0:5432/database\"),\n\t\t\tcty.StringVal(\"search_path\"),\n\t\t\tcty.StringVal(\"schema\"),\n\t\t\tcty.StringVal(\"postgres://postgres:pass@0.0.0.0:5432/database?search_path=schema\"),\n\t\t},\n\t\t{\n\t\t\tcty.StringVal(\"postgres://postgres:pass@0.0.0.0:5432/database?sslmode=disable&search_path=admin&sslmode=disable\"),\n\t\t\tcty.StringVal(\"search_path\"),\n\t\t\tcty.StringVal(\"\"),\n\t\t\tcty.StringVal(\"postgres://postgres:pass@0.0.0.0:5432/database?search_path=&sslmode=disable&sslmode=disable\"),\n\t\t},\n\t}\n\tfor _, test := range tests {\n\t\tt.Run(fmt.Sprintf(\"(%#v,%#v,%#v)\", test.URL, test.Key, test.Value), func(t *testing.T) {\n\t\t\tgot, err := urlQuerySetFunc.Call([]cty.Value{test.URL, test.Key, test.Value})\n\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t\t}\n\t\t\tif !got.RawEquals(test.Want) {\n\t\t\t\tt.Errorf(\"wrong result\\ngot:  %#v\\nwant: %#v\", got, test.Want)\n\t\t\t}\n\t\t\tvar (\n\t\t\t\tf = fmt.Sprintf(\n\t\t\t\t\t`v = urlqueryset(%q, %q, %q)`,\n\t\t\t\t\ttest.URL.AsString(), test.Key.AsString(), test.Value.AsString(),\n\t\t\t\t)\n\t\t\t\td struct {\n\t\t\t\t\tV cty.Value `spec:\"v\"`\n\t\t\t\t}\n\t\t\t)\n\t\t\trequire.NoError(t, New().EvalBytes([]byte(f), &d, nil))\n\t\t\trequire.True(t, d.V.RawEquals(got))\n\t\t})\n\t}\n}\n\nfunc TestURLEscapeFunc(t *testing.T) {\n\tfor _, tt := range []string{\"foo\", \"foo?\", \"foo&\"} {\n\t\tt.Run(tt, func(t *testing.T) {\n\t\t\tgot, err := urlEscapeFunc.Call([]cty.Value{cty.StringVal(tt)})\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t\t}\n\t\t\tif want := url.QueryEscape(tt); got.AsString() != want {\n\t\t\t\tt.Errorf(\"wrong result\\ngot:  %#v\\nwant: %#v\", got, want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestURLUserinfoFunc(t *testing.T) {\n\tu := cty.StringVal(\"mysql://localhost:3306\")\n\t// Only user is provided\n\tgot, err := urlUserinfoFunc.Call([]cty.Value{u, cty.StringVal(\"user\")})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.StringVal(\"mysql://user@localhost:3306\"), got)\n\t// The password is null\n\tgot, err = urlUserinfoFunc.Call([]cty.Value{u, cty.StringVal(\"user\"), cty.NullVal(cty.String)})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.StringVal(\"mysql://user@localhost:3306\"), got)\n\t// Both user and password are provided\n\tgot, err = urlUserinfoFunc.Call([]cty.Value{u, cty.StringVal(\"user\"), cty.StringVal(\"pass\")})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.StringVal(\"mysql://user:pass@localhost:3306\"), got)\n}\n\nfunc TestStartWithFunc(t *testing.T) {\n\tgot, err := startsWithFunc.Call([]cty.Value{cty.StringVal(\"abc\"), cty.StringVal(\"ab\")})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.True, got)\n\tgot, err = startsWithFunc.Call([]cty.Value{cty.StringVal(\"abc\"), cty.StringVal(\"bc\")})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.False, got)\n}\n\nfunc TestEndsWithFunc(t *testing.T) {\n\tgot, err := endsWithFunc.Call([]cty.Value{cty.StringVal(\"abc\"), cty.StringVal(\"ab\")})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.False, got)\n\tgot, err = endsWithFunc.Call([]cty.Value{cty.StringVal(\"abc\"), cty.StringVal(\"bc\")})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.True, got)\n}\n\nfunc TestEmptyFunc(t *testing.T) {\n\tgot, err := emptyFunc.Call([]cty.Value{cty.ListValEmpty(cty.String)})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.True, got)\n\tgot, err = emptyFunc.Call([]cty.Value{cty.SetValEmpty(cty.String)})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.True, got)\n\tgot, err = emptyFunc.Call([]cty.Value{cty.MapValEmpty(cty.String)})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.True, got)\n\tgot, err = emptyFunc.Call([]cty.Value{cty.EmptyTupleVal})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.True, got)\n\tgot, err = emptyFunc.Call([]cty.Value{cty.ListVal([]cty.Value{cty.StringVal(\"a\")})})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.False, got)\n\t// Invalid value.\n\tgot, err = emptyFunc.Call([]cty.Value{cty.StringVal(\"a\")})\n\trequire.EqualError(t, err, \"collection must be a list, a map or a tuple\")\n}\n\nfunc TestRegexpEscapeFunc(t *testing.T) {\n\tgot, err := regexpEscape.Call([]cty.Value{cty.StringVal(\"a|b|c\")})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"a\\\\|b\\\\|c\", got.AsString())\n\tgot, err = regexpEscape.Call([]cty.Value{cty.StringVal(\"abc\")})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"abc\", got.AsString())\n}\n\nfunc TestMakeFileFunc(t *testing.T) {\n\tfn := MakeFileFunc(\"testdata\")\n\t_, err := fn.Call([]cty.Value{cty.StringVal(\"foo\")})\n\trequire.EqualError(t, err, \"base directory must be an absolute path. got: testdata\")\n\tbase, err := filepath.Abs(\"testdata\")\n\trequire.NoError(t, err)\n\tfn = MakeFileFunc(base)\n\tv, err := fn.Call([]cty.Value{cty.StringVal(\"a.hcl\")})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"person \\\"rotemtam\\\" {\\n  hobby = var.hobby\\n}\", v.AsString())\n}\n\nfunc TestMakeGlobFunc(t *testing.T) {\n\tfn := MakeGlobFunc(\"testdata\")\n\t_, err := fn.Call([]cty.Value{cty.StringVal(\"foo\")})\n\trequire.EqualError(t, err, \"base directory must be an absolute path. got: testdata\")\n\n\tbase, err := filepath.Abs(\"testdata\")\n\trequire.NoError(t, err)\n\tfn = MakeGlobFunc(base)\n\tv, err := fn.Call([]cty.Value{cty.StringVal(\"*.hcl\")})\n\trequire.NoError(t, err)\n\n\tvar result []string\n\tfor _, f := range v.AsValueSlice() {\n\t\tp, err := filepath.Rel(base, f.AsString())\n\t\trequire.NoError(t, err)\n\t\tresult = append(result, p)\n\t}\n\trequire.Equal(t, []string{\"a.hcl\", \"b.hcl\", \"variables.hcl\"}, result)\n}\n\nfunc TestMakeFilesetFunc(t *testing.T) {\n\tbase, err := filepath.Abs(\"testdata\")\n\trequire.NoError(t, err)\n\n\tfn := MakeFileSetFunc(base)\n\n\ttests := []struct {\n\t\tname     string\n\t\tpattern  string\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\tname:     \"Simple HCL files\",\n\t\t\tpattern:  \"*.hcl\",\n\t\t\texpected: []string{\"a.hcl\", \"b.hcl\", \"variables.hcl\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Non-existent files\",\n\t\t\tpattern:  \"*.txt\",\n\t\t\texpected: []string{},\n\t\t},\n\t\t{\n\t\t\tname:     \"Nested directories\",\n\t\t\tpattern:  \"**/*.hcl\",\n\t\t\texpected: []string{\"a.hcl\", \"b.hcl\", \"nested/c.hcl\", \"variables.hcl\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Single file\",\n\t\t\tpattern:  \"a.hcl\",\n\t\t\texpected: []string{\"a.hcl\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Files with specific prefix\",\n\t\t\tpattern:  \"a*.hcl\",\n\t\t\texpected: []string{\"a.hcl\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"Files in specific directory\",\n\t\t\tpattern:  \"nested/*.hcl\",\n\t\t\texpected: []string{\"nested/c.hcl\"},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tv, err := fn.Call([]cty.Value{cty.StringVal(tt.pattern)})\n\t\t\trequire.NoError(t, err)\n\t\t\tvar result []string\n\t\t\tfor _, f := range v.AsValueSlice() {\n\t\t\t\tp, err := filepath.Rel(base, f.AsString())\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tresult = append(result, filepath.ToSlash(p))\n\t\t\t}\n\t\t\trequire.ElementsMatch(t, tt.expected, result)\n\t\t})\n\t}\n\n\t// Test with relative base path\n\trelativeFn := MakeFileSetFunc(\"testdata\")\n\t_, err = relativeFn.Call([]cty.Value{cty.StringVal(\"*.hcl\")})\n\trequire.EqualError(t, err, \"base directory must be an absolute path. got: testdata\")\n}\n\nfunc Example_regexpEscapeFunc() {\n\tfor _, f := range []string{\n\t\t`v  = regexpescape(\"a|b|c\")`,\n\t\t`v  = regexpescape(\"abc\")`,\n\t\t`v = regexpescape(<<TAB\nid | name\n---+-----\n1  | foo\nTAB\n)`,\n\t} {\n\t\tvar d struct {\n\t\t\tV string `spec:\"v\"`\n\t\t}\n\t\tif err := New().EvalBytes([]byte(f), &d, nil); err != nil {\n\t\t\tfmt.Println(\"failed to evaluate:\", err)\n\t\t\treturn\n\t\t}\n\t\tfmt.Printf(\"%s\\n\\n\", d.V)\n\t}\n\t// Output:\n\t// a\\|b\\|c\n\t//\n\t// abc\n\t//\n\t// id \\| name\n\t// ---\\+-----\n\t// 1  \\| foo\n}\n\nfunc Example_printFunc() {\n\tfor _, f := range []string{\n\t\t`v  = print(\"a\")`,\n\t\t`v  = print(\"a&b\")`,\n\t\t`v  = print(1)`,\n\t\t`v  = print(true)`,\n\t\t`v  = print(\"hello, world\")`,\n\t\t`v  = print({\"hello\": \"world\"})`,\n\t\t`v  = print([\"hello\", \"world\"])`,\n\t} {\n\t\tvar d struct {\n\t\t\tV cty.Value `spec:\"v\"`\n\t\t}\n\t\tif err := New().EvalBytes([]byte(f), &d, nil); err != nil {\n\t\t\tfmt.Println(\"failed to evaluate:\", err)\n\t\t\treturn\n\t\t}\n\t\tfmt.Printf(\"%#v\\n\\n\", d.V)\n\t}\n\t// Output:\n\t// a\n\t// cty.StringVal(\"a\")\n\t//\n\t// a&b\n\t// cty.StringVal(\"a&b\")\n\t//\n\t// 1\n\t// cty.NumberIntVal(1)\n\t//\n\t// true\n\t// cty.True\n\t//\n\t// hello, world\n\t// cty.StringVal(\"hello, world\")\n\t//\n\t// {\"hello\":\"world\"}\n\t// cty.ObjectVal(map[string]cty.Value{\"hello\":cty.StringVal(\"world\")})\n\t//\n\t// [\"hello\",\"world\"]\n\t// cty.ListVal([]cty.Value{cty.StringVal(\"hello\"), cty.StringVal(\"world\")})\n\t//\n}\n\nfunc TestYAMLMerge(t *testing.T) {\n\tgot, err := yamlMergeFunc.Call([]cty.Value{\n\t\tcty.StringVal(\"map:\\n  zzz: true\\n  foo:\\n    - bar\"),\n\t\tcty.StringVal(\"map:\\n  bar:\\n    - baz\\n  foo:\\n    - bar\"),\n\t\tcty.StringVal(\"map:\\n  map:\\n    baz: true\\n    foo: false\"),\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.StringVal(`map:\n    bar:\n        - baz\n    foo:\n        - bar\n        - bar\n    map:\n        baz: true\n        foo: false\n    zzz: true\n`), got)\n\n\tgot, err = yamlMergeFunc.Call([]cty.Value{\n\t\tcty.StringVal(\"map:\\n  zzz: true\\n  foo:\\n    - bar\"),\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, cty.StringVal(`map:\n  zzz: true\n  foo:\n    - bar`), got)\n\n\t_, err = yamlMergeFunc.Call([]cty.Value{\n\t\tcty.StringVal(\"map:\\n  zzz: true\\n  foo:\\n    - bar\"),\n\t\tcty.NullVal(cty.String),\n\t\tcty.StringVal(\"map:\\n  zzz:\\n    - baz\"),\n\t})\n\trequire.EqualError(t, err, \"yamlmerge: failed to merge yaml: key zzz is defined in both src and dst, but has a different type\")\n\n\t_, err = yamlMergeFunc.Call([]cty.Value{\n\t\tcty.StringVal(\"map:\\n  zzz: true\\n  foo:\\n    - bar\"),\n\t\tcty.StringVal(\"map:\\n  zzz:\\n    foo: true\"),\n\t})\n\trequire.EqualError(t, err, \"yamlmerge: failed to merge yaml: key zzz is defined in both src and dst, but has a different type\")\n}\n"
  },
  {
    "path": "schemahcl/testdata/a.hcl",
    "content": "person \"rotemtam\" {\n  hobby = var.hobby\n}"
  },
  {
    "path": "schemahcl/testdata/b.hcl",
    "content": "person \"tzuri\" {\n  hobby = \"ice-cream\"\n  parent = person.rotemtam\n}"
  },
  {
    "path": "schemahcl/testdata/nested/c.hcl",
    "content": ""
  },
  {
    "path": "schemahcl/testdata/variables.hcl",
    "content": "variable \"hobby\" {\n  type = string\n}"
  },
  {
    "path": "schemahcl/types.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/go-openapi/inflect\"\n)\n\n// PrintType returns the string representation of a column type which can be parsed\n// by the driver into a schema.Type.\nfunc (r *TypeRegistry) PrintType(typ *Type) (string, error) {\n\tspec, ok := r.findT(typ.T)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"specutil: type %q not found in registry\", typ.T)\n\t}\n\tif len(spec.Attributes) == 0 {\n\t\treturn typ.T, nil\n\t}\n\tvar (\n\t\targs        []string\n\t\tmid, suffix string\n\t)\n\tfor _, arg := range typ.Attrs {\n\t\t// TODO(rotemtam): make this part of the TypeSpec\n\t\tif arg.K == \"unsigned\" {\n\t\t\tb, err := arg.Bool()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\tif b {\n\t\t\t\tsuffix += \" unsigned\"\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tattr, ok := spec.Attr(arg.K)\n\t\tif !ok {\n\t\t\treturn \"\", fmt.Errorf(\"specutil: attribute %q not found in typespec %q\", arg.K, typ.T)\n\t\t}\n\t\targs = append(args, valueArgs(attr, arg.V)...)\n\t}\n\tif len(args) > 0 {\n\t\tmid = \"(\" + strings.Join(args, \",\") + \")\"\n\t}\n\treturn typ.T + mid + suffix, nil\n}\n\n// TypeRegistry is a collection of *schemahcl.TypeSpec.\ntype TypeRegistry struct {\n\tr      []*TypeSpec\n\tspec   func(schema.Type) (*Type, error)\n\tparser func(string) (schema.Type, error)\n}\n\n// WithFormatter configures the registry to use a formatting function for printing\n// schema.Type as string.\nfunc WithFormatter(f func(schema.Type) (string, error)) TypeRegistryOption {\n\treturn func(registry *TypeRegistry) error {\n\t\tregistry.spec = func(t schema.Type) (*Type, error) {\n\t\t\ts, err := f(t)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"specutil: cannot format type %T: %w\", t, err)\n\t\t\t}\n\t\t\treturn &Type{T: s}, nil\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// WithSpecFunc configures the registry to use the given function for converting\n// a schema.Type to schemahcl.Type\nfunc WithSpecFunc(spec func(schema.Type) (*Type, error)) TypeRegistryOption {\n\treturn func(registry *TypeRegistry) error {\n\t\tregistry.spec = spec\n\t\treturn nil\n\t}\n}\n\n// WithParser configures the registry to use a parsing function for converting\n// a string to a schema.Type.\nfunc WithParser(parser func(string) (schema.Type, error)) TypeRegistryOption {\n\treturn func(registry *TypeRegistry) error {\n\t\tregistry.parser = parser\n\t\treturn nil\n\t}\n}\n\n// Register adds one or more TypeSpec to the registry.\nfunc (r *TypeRegistry) Register(specs ...*TypeSpec) error {\n\tfor _, s := range specs {\n\t\tif err := validSpec(s); err != nil {\n\t\t\treturn fmt.Errorf(\"specutil: invalid typespec %q: %w\", s.Name, err)\n\t\t}\n\t\tif _, exists := r.findT(s.T); exists {\n\t\t\treturn fmt.Errorf(\"specutil: type with T of %q already registered\", s.T)\n\t\t}\n\t\tif _, exists := r.findName(s.Name); exists {\n\t\t\treturn fmt.Errorf(\"specutil: type with name of %q already registered\", s.T)\n\t\t}\n\t\tr.r = append(r.r, s)\n\t}\n\treturn nil\n}\n\nfunc validSpec(typeSpec *TypeSpec) error {\n\tvar seenOptional bool\n\tfor i, attr := range typeSpec.Attributes {\n\t\tif attr.Kind == reflect.Slice && i < len(typeSpec.Attributes)-1 {\n\t\t\treturn fmt.Errorf(\"attr %q is of kind slice but not last\", attr.Name)\n\t\t}\n\t\tif seenOptional && attr.Required {\n\t\t\treturn fmt.Errorf(\"attr %q required after optional attr\", attr.Name)\n\t\t}\n\t\tseenOptional = !attr.Required\n\t}\n\treturn nil\n}\n\n// TypeRegistryOption configures a TypeRegistry.\ntype TypeRegistryOption func(*TypeRegistry) error\n\n// WithSpecs configures the registry to register the given list of type specs.\nfunc WithSpecs(specs ...*TypeSpec) TypeRegistryOption {\n\treturn func(registry *TypeRegistry) error {\n\t\tif err := registry.Register(specs...); err != nil {\n\t\t\treturn fmt.Errorf(\"failed registering types: %s\", err)\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// NewRegistry creates a new *TypeRegistry, registers the provided types and panics\n// if an error occurs.\nfunc NewRegistry(opts ...TypeRegistryOption) *TypeRegistry {\n\tr := &TypeRegistry{}\n\tfor _, opt := range opts {\n\t\tif err := opt(r); err != nil {\n\t\t\tlog.Fatalf(\"failed configuring registry: %s\", err)\n\t\t}\n\t}\n\treturn r\n}\n\n// findName searches the registry for types that have the provided name.\nfunc (r *TypeRegistry) findName(name string) (*TypeSpec, bool) {\n\tfor _, current := range r.r {\n\t\tif current.Name == name {\n\t\t\treturn current, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// findT searches the registry for types that have the provided T.\nfunc (r *TypeRegistry) findT(t string) (*TypeSpec, bool) {\n\tfor _, current := range r.r {\n\t\tif current.T == t {\n\t\t\treturn current, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Convert converts the schema.Type to a *schemahcl.Type.\nfunc (r *TypeRegistry) Convert(typ schema.Type) (*Type, error) {\n\tif ut, ok := typ.(*schema.UnsupportedType); ok {\n\t\treturn &Type{\n\t\t\tT: ut.T,\n\t\t}, nil\n\t}\n\trv := reflect.ValueOf(typ)\n\tif rv.Kind() == reflect.Ptr {\n\t\trv = rv.Elem()\n\t}\n\tif !rv.IsValid() {\n\t\treturn nil, errors.New(\"specutil: invalid schema.Type on Convert\")\n\t}\n\ttypeSpec, ok := r.findType(rv)\n\tif !ok {\n\t\treturn r.spec(typ)\n\t}\n\tif typeSpec.ToSpec != nil {\n\t\treturn typeSpec.ToSpec(typ)\n\t}\n\ts := &Type{T: typeSpec.T}\n\t// Iterate the attributes in reverse order, so we can skip zero value and optional attrs.\n\tfor i := len(typeSpec.Attributes) - 1; i >= 0; i-- {\n\t\tattr := typeSpec.Attributes[i]\n\t\tn := inflect.Camelize(attr.Name)\n\t\tfield := rv.FieldByName(n)\n\t\t// If TypeSpec has an attribute that isn't mapped to a field on the schema.Type skip it.\n\t\tif !field.IsValid() || field.Kind() == reflect.Ptr && field.IsNil() {\n\t\t\tcontinue\n\t\t}\n\t\tif field = reflect.Indirect(field); field.Kind() != attr.Kind {\n\t\t\treturn nil, errors.New(\"incompatible kinds on typespec attr and typefield\")\n\t\t}\n\t\tswitch attr.Kind {\n\t\tcase reflect.Int, reflect.Int64:\n\t\t\tv := int(field.Int())\n\t\t\tif v == 0 && len(s.Attrs) == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ts.Attrs = append([]*Attr{IntAttr(attr.Name, v)}, s.Attrs...)\n\t\tcase reflect.Bool:\n\t\t\tv := field.Bool()\n\t\t\tif !v && len(s.Attrs) == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ts.Attrs = append([]*Attr{BoolAttr(attr.Name, v)}, s.Attrs...)\n\t\tcase reflect.String:\n\t\t\tv := field.String()\n\t\t\tif v == \"\" && len(s.Attrs) == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ts.Attrs = append([]*Attr{StringAttr(attr.Name, v)}, s.Attrs...)\n\t\tcase reflect.Slice:\n\t\t\tvs, ok := field.Interface().([]string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"specutil: unsupported slice type %T\", field.Interface())\n\t\t\t}\n\t\t\ts.Attrs = append([]*Attr{StringsAttr(attr.Name, vs...)}, s.Attrs...)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"specutil: unsupported attr kind %s for attribute %q of %q\", attr.Kind, attr.Name, typeSpec.Name)\n\t\t}\n\t}\n\treturn s, nil\n}\n\nfunc (r *TypeRegistry) findType(rv reflect.Value) (*TypeSpec, bool) {\n\ttf := rv.FieldByName(\"T\")\n\tif tf.IsValid() && tf.Kind() == reflect.String {\n\t\tname := tf.String()\n\t\tif typeSpec, ok := r.findT(name); ok {\n\t\t\treturn typeSpec, true\n\t\t}\n\t}\n\tif typeSpec, ok := r.findRType(rv.Type()); ok {\n\t\treturn typeSpec, true\n\t}\n\treturn nil, false\n}\n\nfunc (r *TypeRegistry) findRType(rt reflect.Type) (*TypeSpec, bool) {\n\tfor _, ts := range r.Specs() {\n\t\tif ts.RType != nil && ts.RType == rt {\n\t\t\treturn ts, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Specs returns the TypeSpecs in the registry.\nfunc (r *TypeRegistry) Specs() []*TypeSpec {\n\treturn r.r\n}\n\n// Type converts a *schemahcl.Type into a schema.Type.\nfunc (r *TypeRegistry) Type(typ *Type, extra []*Attr) (schema.Type, error) {\n\tif typ == nil {\n\t\treturn nil, errors.New(\"specutil: nil type\")\n\t}\n\ttypeSpec, ok := r.findT(typ.T)\n\tif !ok {\n\t\treturn r.parser(typ.T)\n\t}\n\tnfa := typeNonFuncArgs(typeSpec)\n\tpicked := pickTypeAttrs(extra, nfa)\n\tcp := &Type{\n\t\tT: typ.T,\n\t}\n\tcp.Attrs = appendIfNotExist(typ.Attrs, picked)\n\tif typeSpec.FromSpec != nil {\n\t\treturn typeSpec.FromSpec(cp)\n\t}\n\tprintType, err := r.PrintType(cp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn r.parser(printType)\n}\n\n// TypeSpecOption configures a schemahcl.TypeSpec.\ntype TypeSpecOption func(*TypeSpec)\n\n// WithAttributes returns an attributes TypeSpecOption.\nfunc WithAttributes(attrs ...*TypeAttr) TypeSpecOption {\n\treturn func(spec *TypeSpec) {\n\t\tspec.Attributes = attrs\n\t}\n}\n\n// WithTypeFormatter allows overriding the Format function for the Type.\nfunc WithTypeFormatter(f func(*Type) (string, error)) TypeSpecOption {\n\treturn func(spec *TypeSpec) {\n\t\tspec.Format = f\n\t}\n}\n\n// WithFromSpec allows configuring the FromSpec convert function using functional options.\nfunc WithFromSpec(f func(*Type) (schema.Type, error)) TypeSpecOption {\n\treturn func(spec *TypeSpec) {\n\t\tspec.FromSpec = f\n\t}\n}\n\n// WithToSpec allows configuring the ToSpec convert function using functional options.\nfunc WithToSpec(f func(schema.Type) (*Type, error)) TypeSpecOption {\n\treturn func(spec *TypeSpec) {\n\t\tspec.ToSpec = f\n\t}\n}\n\n// NewTypeSpec returns a TypeSpec with the provided name.\nfunc NewTypeSpec(name string, opts ...TypeSpecOption) *TypeSpec {\n\treturn AliasTypeSpec(name, name, opts...)\n}\n\n// AliasTypeSpec returns a TypeSpec with the provided name.\nfunc AliasTypeSpec(name, dbType string, opts ...TypeSpecOption) *TypeSpec {\n\tts := &TypeSpec{\n\t\tName: name,\n\t\tT:    dbType,\n\t}\n\tfor _, opt := range opts {\n\t\topt(ts)\n\t}\n\treturn ts\n}\n\n// SizeTypeAttr returns a TypeAttr for a size attribute.\nfunc SizeTypeAttr(required bool) *TypeAttr {\n\treturn &TypeAttr{\n\t\tName:     \"size\",\n\t\tKind:     reflect.Int,\n\t\tRequired: required,\n\t}\n}\n\n// PrecisionTypeAttr returns a TypeAttr for a precision attribute.\nfunc PrecisionTypeAttr() *TypeAttr {\n\treturn &TypeAttr{\n\t\tName: \"precision\",\n\t\tKind: reflect.Int,\n\t}\n}\n\n// ScaleTypeAttr returns a TypeAttr for a scale attribute.\nfunc ScaleTypeAttr() *TypeAttr {\n\treturn &TypeAttr{\n\t\tName: \"scale\",\n\t\tKind: reflect.Int,\n\t}\n}\n\n// typeNonFuncArgs returns the type attributes that are NOT configured via arguments to the\n// type definition, `int unsigned`.\nfunc typeNonFuncArgs(spec *TypeSpec) []*TypeAttr {\n\tvar args []*TypeAttr\n\tfor _, attr := range spec.Attributes {\n\t\t// TODO(rotemtam): this should be defined on the TypeSpec.\n\t\tif attr.Name == \"unsigned\" {\n\t\t\targs = append(args, attr)\n\t\t}\n\t}\n\treturn args\n}\n\n// pickTypeAttrs returns the relevant Attrs matching the wanted TypeAttrs.\nfunc pickTypeAttrs(src []*Attr, wanted []*TypeAttr) []*Attr {\n\tkeys := make(map[string]struct{})\n\tfor _, w := range wanted {\n\t\tkeys[w.Name] = struct{}{}\n\t}\n\tvar picked []*Attr\n\tfor _, attr := range src {\n\t\tif _, ok := keys[attr.K]; ok {\n\t\t\tpicked = append(picked, attr)\n\t\t}\n\t}\n\treturn picked\n}\n\nfunc appendIfNotExist(base []*Attr, additional []*Attr) []*Attr {\n\texists := make(map[string]struct{})\n\tfor _, attr := range base {\n\t\texists[attr.K] = struct{}{}\n\t}\n\tfor _, attr := range additional {\n\t\tif _, ok := exists[attr.K]; !ok {\n\t\t\tbase = append(base, attr)\n\t\t}\n\t}\n\treturn base\n}\n"
  },
  {
    "path": "schemahcl/types_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schemahcl\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTypePrint(t *testing.T) {\n\tintSpec := &TypeSpec{\n\t\tName: \"int\",\n\t\tT:    \"int\",\n\t\tAttributes: []*TypeAttr{\n\t\t\tunsignedTypeAttr(),\n\t\t},\n\t}\n\tfor _, tt := range []struct {\n\t\tspec     *TypeSpec\n\t\ttyp      *Type\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tspec:     intSpec,\n\t\t\ttyp:      &Type{T: \"int\"},\n\t\t\texpected: \"int\",\n\t\t},\n\t\t{\n\t\t\tspec:     intSpec,\n\t\t\ttyp:      &Type{T: \"int\", Attrs: []*Attr{BoolAttr(\"unsigned\", true)}},\n\t\t\texpected: \"int unsigned\",\n\t\t},\n\t\t{\n\t\t\tspec: &TypeSpec{\n\t\t\t\tName:       \"float\",\n\t\t\t\tT:          \"float\",\n\t\t\t\tAttributes: []*TypeAttr{unsignedTypeAttr()},\n\t\t\t},\n\t\t\ttyp:      &Type{T: \"float\", Attrs: []*Attr{BoolAttr(\"unsigned\", true)}},\n\t\t\texpected: \"float unsigned\",\n\t\t},\n\t\t{\n\t\t\tspec: &TypeSpec{\n\t\t\t\tT:    \"varchar\",\n\t\t\t\tName: \"varchar\",\n\t\t\t\tAttributes: []*TypeAttr{\n\t\t\t\t\t{Name: \"size\", Kind: reflect.Int, Required: true},\n\t\t\t\t},\n\t\t\t},\n\t\t\ttyp:      &Type{T: \"varchar\", Attrs: []*Attr{IntAttr(\"size\", 255)}},\n\t\t\texpected: \"varchar(255)\",\n\t\t},\n\t} {\n\t\tt.Run(tt.expected, func(t *testing.T) {\n\t\t\tr := &TypeRegistry{}\n\t\t\terr := r.Register(tt.spec)\n\t\t\trequire.NoError(t, err)\n\t\t\ts, err := r.PrintType(tt.typ)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.EqualValues(t, tt.expected, s)\n\t\t})\n\t}\n}\n\nfunc TestRegistry(t *testing.T) {\n\tr := &TypeRegistry{}\n\ttext := &TypeSpec{Name: \"text\", T: \"text\"}\n\terr := r.Register(text)\n\trequire.NoError(t, err)\n\terr = r.Register(text)\n\trequire.EqualError(t, err, `specutil: type with T of \"text\" already registered`)\n\tspec, ok := r.findName(\"text\")\n\trequire.True(t, ok)\n\trequire.EqualValues(t, spec, text)\n}\n\nfunc TestValidSpec(t *testing.T) {\n\tregistry := &TypeRegistry{}\n\terr := registry.Register(&TypeSpec{\n\t\tName: \"X\",\n\t\tT:    \"X\",\n\t\tAttributes: []*TypeAttr{\n\t\t\t{Name: \"a\", Required: false, Kind: reflect.Slice},\n\t\t\t{Name: \"b\", Required: true},\n\t\t},\n\t})\n\trequire.EqualError(t, err, `specutil: invalid typespec \"X\": attr \"a\" is of kind slice but not last`)\n\terr = registry.Register(&TypeSpec{\n\t\tName: \"Z\",\n\t\tT:    \"Z\",\n\t\tAttributes: []*TypeAttr{\n\t\t\t{Name: \"b\", Required: true},\n\t\t\t{Name: \"a\", Required: false, Kind: reflect.Slice},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\terr = registry.Register(&TypeSpec{\n\t\tName: \"Z2\",\n\t\tT:    \"Z2\",\n\t\tAttributes: []*TypeAttr{\n\t\t\t{Name: \"a\", Required: false, Kind: reflect.Slice},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\terr = registry.Register(&TypeSpec{\n\t\tName: \"X\",\n\t\tT:    \"X\",\n\t\tAttributes: []*TypeAttr{\n\t\t\t{Name: \"a\", Required: false},\n\t\t\t{Name: \"b\", Required: true},\n\t\t},\n\t})\n\trequire.EqualError(t, err, `specutil: invalid typespec \"X\": attr \"b\" required after optional attr`)\n\terr = registry.Register(&TypeSpec{\n\t\tName: \"X\",\n\t\tT:    \"X\",\n\t\tAttributes: []*TypeAttr{\n\t\t\t{Name: \"a\", Required: true},\n\t\t\t{Name: \"b\", Required: false},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\terr = registry.Register(&TypeSpec{\n\t\tName: \"Y\",\n\t\tT:    \"Y\",\n\t\tAttributes: []*TypeAttr{\n\t\t\t{Name: \"a\", Required: false},\n\t\t\t{Name: \"b\", Required: false},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n}\n\nfunc TestRegistryConvert(t *testing.T) {\n\tr := &TypeRegistry{}\n\terr := r.Register(\n\t\tNewTypeSpec(\"varchar\", WithAttributes(SizeTypeAttr(true))),\n\t\tNewTypeSpec(\"int\", WithAttributes(unsignedTypeAttr())),\n\t\tNewTypeSpec(\n\t\t\t\"decimal\",\n\t\t\tWithAttributes(\n\t\t\t\tPrecisionTypeAttr(),\n\t\t\t\tScaleTypeAttr(),\n\t\t\t),\n\t\t),\n\t\tNewTypeSpec(\"enum\", WithAttributes(&TypeAttr{\n\t\t\tName:     \"values\",\n\t\t\tKind:     reflect.Slice,\n\t\t\tRequired: true,\n\t\t})),\n\t)\n\trequire.NoError(t, err)\n\tfor _, tt := range []struct {\n\t\ttyp         schema.Type\n\t\texpected    *Type\n\t\texpectedErr string\n\t}{\n\t\t{\n\t\t\ttyp:      &schema.StringType{T: \"varchar\", Size: 255},\n\t\t\texpected: &Type{T: \"varchar\", Attrs: []*Attr{IntAttr(\"size\", 255)}},\n\t\t},\n\t\t{\n\t\t\ttyp:      &schema.IntegerType{T: \"int\", Unsigned: true},\n\t\t\texpected: &Type{T: \"int\", Attrs: []*Attr{BoolAttr(\"unsigned\", true)}},\n\t\t},\n\t\t{\n\t\t\ttyp:      &schema.IntegerType{T: \"int\", Unsigned: true},\n\t\t\texpected: &Type{T: \"int\", Attrs: []*Attr{BoolAttr(\"unsigned\", true)}},\n\t\t},\n\t\t{\n\t\t\ttyp: &schema.DecimalType{T: \"decimal\", Precision: 10, Scale: 2}, // decimal(10,2)\n\t\t\texpected: &Type{T: \"decimal\", Attrs: []*Attr{\n\t\t\t\tIntAttr(\"precision\", 10),\n\t\t\t\tIntAttr(\"scale\", 2),\n\t\t\t}},\n\t\t},\n\t\t{\n\t\t\ttyp: &schema.DecimalType{T: \"decimal\", Precision: 10}, // decimal(10)\n\t\t\texpected: &Type{T: \"decimal\", Attrs: []*Attr{\n\t\t\t\tIntAttr(\"precision\", 10),\n\t\t\t}},\n\t\t},\n\t\t{\n\t\t\ttyp: &schema.DecimalType{T: \"decimal\", Scale: 2}, // decimal(0,2)\n\t\t\texpected: &Type{T: \"decimal\", Attrs: []*Attr{\n\t\t\t\tIntAttr(\"precision\", 0),\n\t\t\t\tIntAttr(\"scale\", 2),\n\t\t\t}},\n\t\t},\n\t\t{\n\t\t\ttyp:      &schema.DecimalType{T: \"decimal\"}, // decimal\n\t\t\texpected: &Type{T: \"decimal\"},\n\t\t},\n\t\t{\n\t\t\ttyp: &schema.EnumType{T: \"enum\", Values: []string{\"on\", \"off\"}},\n\t\t\texpected: &Type{T: \"enum\", Attrs: []*Attr{\n\t\t\t\tStringsAttr(\"values\", \"on\", \"off\"),\n\t\t\t}},\n\t\t},\n\t\t{\n\t\t\ttyp:         nil,\n\t\t\texpected:    &Type{},\n\t\t\texpectedErr: \"specutil: invalid schema.Type on Convert\",\n\t\t},\n\t} {\n\t\tt.Run(tt.expected.T, func(t *testing.T) {\n\t\t\tconvert, err := r.Convert(tt.typ)\n\t\t\tif tt.expectedErr != \"\" {\n\t\t\t\trequire.EqualError(t, err, tt.expectedErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.EqualValues(t, tt.expected, convert)\n\t\t})\n\t}\n}\n\nfunc unsignedTypeAttr() *TypeAttr {\n\treturn &TypeAttr{\n\t\tName: \"unsigned\",\n\t\tKind: reflect.Bool,\n\t}\n}\n"
  },
  {
    "path": "sdk/recordriver/driver.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// package recordriver provides a driver for database/sql which records queries and statements\n// and allows you to set responses for queries. It is used for testing or providing a runtime replacement\n// for a real database in cases where you want to learn the queries and statements that are executed.\n\npackage recordriver\n\nimport (\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n)\n\nfunc init() {\n\tsql.Register(\"recordriver\", &drv{})\n}\n\nvar (\n\tsessions = map[string]*session{}\n\tmu       sync.Mutex\n)\n\ntype (\n\t// session is a session of recordriver which records queries and statements.\n\tsession struct {\n\t\tQueries    []string\n\t\tStatements []string\n\t\tresponses  map[string]*Response\n\t}\n\t// Response is a response to a query.\n\tResponse struct {\n\t\tCols []string\n\t\tData [][]driver.Value\n\t}\n\tdrv  struct{}\n\tconn struct {\n\t\tsession string\n\t}\n\tstmt struct {\n\t\tquery   string\n\t\tsession string\n\t}\n\ttx          struct{}\n\temptyResult struct{}\n)\n\n// Stmts returns the statements as a string, separated by semicolons and newlines.\nfunc (s *session) Stmts() string {\n\tvar sb strings.Builder\n\tfor _, stmt := range s.Statements {\n\t\tsb.WriteString(stmt)\n\t\tsb.WriteString(\";\\n\")\n\t}\n\treturn sb.String()\n}\n\n// Session returns the session with the given name and reports whether it exists.\n// revive:disable-next-line unexported-return\nfunc Session(name string) (*session, bool) {\n\tmu.Lock()\n\tdefer mu.Unlock()\n\th, ok := sessions[name]\n\treturn h, ok\n}\n\n// SetResponse sets the response for the given session and query.\nfunc SetResponse(s string, query string, resp *Response) {\n\tmu.Lock()\n\tdefer mu.Unlock()\n\tif _, ok := sessions[s]; !ok {\n\t\tsessions[s] = &session{\n\t\t\tresponses: make(map[string]*Response),\n\t\t}\n\t}\n\tsessions[s].responses[query] = resp\n}\n\n// Open returns a new connection to the database.\nfunc (d *drv) Open(name string) (driver.Conn, error) {\n\tmu.Lock()\n\tdefer mu.Unlock()\n\tif _, ok := sessions[name]; !ok {\n\t\tsessions[name] = &session{\n\t\t\tresponses: make(map[string]*Response),\n\t\t}\n\t}\n\treturn &conn{session: name}, nil\n}\n\n// Prepare returns a prepared statement, bound to this connection.\nfunc (c *conn) Prepare(query string) (driver.Stmt, error) {\n\treturn &stmt{query: query, session: c.session}, nil\n}\n\n// Close closes the connection.\nfunc (c *conn) Close() error {\n\tmu.Lock()\n\tdefer mu.Unlock()\n\tdelete(sessions, c.session)\n\treturn nil\n}\n\n// Begin starts and returns a new transaction.\nfunc (c *conn) Begin() (driver.Tx, error) {\n\treturn &tx{}, nil\n}\n\n// Commit commits the transaction. It is a noop.\nfunc (*tx) Commit() error {\n\treturn nil\n}\n\n// Rollback rolls back the transaction. It is a noop.\nfunc (*tx) Rollback() error {\n\treturn nil\n}\n\n// Close closes the statement.\nfunc (*stmt) Close() error {\n\treturn nil\n}\n\n// NumInput returns the number of placeholder parameters. Reporting -1 does not know the\n// number of parameters.\nfunc (*stmt) NumInput() int {\n\treturn -1\n}\n\n// Exec executes a query that doesn't return rows, such as an CREATE or ALTER TABLE.\nfunc (s *stmt) Exec(_ []driver.Value) (driver.Result, error) {\n\tmu.Lock()\n\tdefer mu.Unlock()\n\tsessions[s.session].Statements = append(sessions[s.session].Statements, s.query)\n\treturn emptyResult{}, nil\n}\n\n// Query executes a query that may return rows, such as an SELECT.\nfunc (s *stmt) Query(_ []driver.Value) (driver.Rows, error) {\n\tmu.Lock()\n\tdefer mu.Unlock()\n\tsess := s.session\n\tsessions[sess].Queries = append(sessions[sess].Queries, s.query)\n\tif resp, ok := sessions[sess].responses[s.query]; ok {\n\t\treturn resp.clone(), nil\n\t}\n\treturn &Response{}, nil\n}\n\n// Columns returns the names of the columns in the result set.\nfunc (r *Response) Columns() []string {\n\treturn r.Cols\n}\n\n// Close closes the rows iterator. It is a noop.\nfunc (*Response) Close() error {\n\treturn nil\n}\n\nfunc (r *Response) clone() *Response {\n\treturn &Response{\n\t\tCols: r.Cols[:],\n\t\tData: r.Data[:],\n\t}\n}\n\n// Next is called to populate the next row of data into the provided slice.\nfunc (r *Response) Next(dest []driver.Value) error {\n\tif len(r.Data) == 0 {\n\t\treturn io.EOF\n\t}\n\tcopy(dest, r.Data[0])\n\tr.Data = r.Data[1:]\n\treturn nil\n}\n\n// LastInsertId returns the integer generated by the database in response to a command. LastInsertId\n// always returns a value of 0.\nfunc (emptyResult) LastInsertId() (int64, error) {\n\treturn 0, nil\n}\n\n// RowsAffected returns the number of rows affected by the query. RowsAffected always returns a\n// value of 0.\nfunc (emptyResult) RowsAffected() (int64, error) {\n\treturn 0, nil\n}\n"
  },
  {
    "path": "sdk/recordriver/driver_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage recordriver\n\nimport (\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDriver(t *testing.T) {\n\tdb, err := sql.Open(\"recordriver\", \"t1\")\n\trequire.NoError(t, err)\n\tdefer db.Close()\n\tSetResponse(\"t1\", \"select sqlite_version()\", &Response{\n\t\tCols: []string{\"sqlite_version()\"},\n\t\tData: [][]driver.Value{{\"3.30.1\"}},\n\t})\n\tfor i := 0; i < 3; i++ {\n\t\tquery, err := db.Query(\"select sqlite_version()\")\n\t\trequire.NoError(t, err)\n\t\tdefer query.Close()\n\t\tvar rows []string\n\t\tfor query.Next() {\n\t\t\tvar version string\n\t\t\terr = query.Scan(&version)\n\t\t\trequire.NoError(t, err)\n\t\t\trows = append(rows, version)\n\t\t\trequire.Equal(t, \"3.30.1\", version)\n\t\t}\n\t\trequire.Len(t, rows, 1)\n\t\thi, ok := Session(\"t1\")\n\t\trequire.True(t, ok)\n\t\trequire.Len(t, hi.Queries, i+1)\n\n\t}\n}\n\nfunc TestInputs(t *testing.T) {\n\tdb, err := sql.Open(\"recordriver\", \"t1\")\n\trequire.NoError(t, err)\n\tdefer db.Close()\n\t_, err = db.Query(\"select * from t where id = ?\", 1)\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "sdk/tmplrun/testdata/app.tmpl",
    "content": "package main\n\nimport (\n  \"fmt\"\n\n  \"ariga.io/atlas/sdk/tmplrun/testdata\"\n)\n\nfunc main() {\n  fmt.Println(\"{{ .Message }}\", testdata.Foo())\n}"
  },
  {
    "path": "sdk/tmplrun/testdata/foo.go",
    "content": "//go:build testdata\n\npackage testdata\n\nfunc Foo() string {\n\treturn \"foo\"\n}\n"
  },
  {
    "path": "sdk/tmplrun/tmplrun.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// package tmplrun provides a Runner for templated go programs. It is commonly used\n// by Go Atlas providers to compile ad-hoc programs that emit the desired SQL schema for\n// data models defined for Go ORMs.\n\npackage tmplrun\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"go/format\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"text/template\"\n\t\"time\"\n)\n\ntype (\n\t// Runner is a go template runner.  It accepts a go template and data, and runs the\n\t// rendered template as a go program.\n\tRunner struct {\n\t\tname      string\n\t\ttmpl      *template.Template\n\t\tbuildTags string\n\t}\n\t// Option is a function that configures the Runner.\n\tOption func(*Runner)\n)\n\n// WithBuildTags sets the build tags for the Runner.\nfunc WithBuildTags(tags string) Option {\n\treturn func(r *Runner) {\n\t\tr.buildTags = tags\n\t}\n}\n\n// New returns a new Runner.\nfunc New(name string, tmpl *template.Template, opts ...Option) *Runner {\n\tr := &Runner{name: name, tmpl: tmpl}\n\tfor _, opt := range opts {\n\t\topt(r)\n\t}\n\treturn r\n}\n\n// Run runs the template and returns the output.\nfunc (r *Runner) Run(data any) (string, error) {\n\tvar buf bytes.Buffer\n\tif err := r.tmpl.Execute(&buf, data); err != nil {\n\t\treturn \"\", err\n\t}\n\ts, err := format.Source(buf.Bytes())\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn r.goRun(s)\n}\n\nfunc (r *Runner) goRun(src []byte) (string, error) {\n\tdir := fmt.Sprintf(\".%s\", r.name)\n\tif err := os.MkdirAll(dir, os.ModePerm); err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer os.RemoveAll(dir)\n\ttarget := fmt.Sprintf(\"%s/%s.go\", dir, r.filename(r.name))\n\tif err := os.WriteFile(target, src, 0600); err != nil {\n\t\treturn \"\", fmt.Errorf(\"%s: write file %s: %w\", r.name, target, err)\n\t}\n\treturn goRun(target, r.buildTags)\n}\n\nfunc (r *Runner) filename(pkg string) string {\n\tname := strings.ReplaceAll(pkg, \"/\", \"_\")\n\treturn fmt.Sprintf(\"%s_%s_%d\", r.name, name, time.Now().Unix())\n}\n\n// run 'go run' command and return its output.\nfunc goRun(target, buildTags string) (string, error) {\n\ts, err := gocmd(\"run\", buildTags, target)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"tmplrun: %s\", err)\n\t}\n\treturn s, nil\n}\n\n// goCmd runs a go command and returns its output.\nfunc gocmd(command, buildTags, target string) (string, error) {\n\targs := []string{command}\n\tif buildTags != \"\" {\n\t\targs = append(args, \"-tags\", buildTags)\n\t}\n\targs = append(args, target)\n\tcmd := exec.Command(\"go\", args...)\n\tstderr := bytes.NewBuffer(nil)\n\tstdout := bytes.NewBuffer(nil)\n\tcmd.Stdout, cmd.Stderr = stdout, stderr\n\tif err := cmd.Run(); err != nil {\n\t\treturn \"\", errors.New(stderr.String())\n\t}\n\treturn stdout.String(), nil\n}\n"
  },
  {
    "path": "sdk/tmplrun/tmplrun_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage tmplrun\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\t\"text/template\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nvar (\n\t//go:embed testdata/app.tmpl\n\ttestTmpl   string\n\tloaderTmpl = template.Must(template.New(\"loader\").Parse(testTmpl))\n)\n\nfunc TestRunner(t *testing.T) {\n\trunner := New(\"test\", loaderTmpl, WithBuildTags(\"testdata\"))\n\tout, err := runner.Run(struct {\n\t\tMessage string\n\t}{\n\t\tMessage: \"Hello, World!\",\n\t})\n\trequire.NoError(t, err)\n\trequire.Contains(t, out, \"Hello, World! foo\")\n}\n"
  },
  {
    "path": "sql/internal/spectest/spectest.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage spectest\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\n// RegistrySanityTest runs a sanity for a TypeRegistry, generated a dummy *schemahcl.Type\n// then converting it to a schema.Type and back to a *schemahcl.Type.\nfunc RegistrySanityTest(t *testing.T, registry *schemahcl.TypeRegistry, skip []string) {\n\tfor _, ts := range registry.Specs() {\n\t\tif contains(ts.Name, skip) {\n\t\t\tcontinue\n\t\t}\n\t\tt.Run(ts.Name, func(t *testing.T) {\n\t\t\t_, err := registry.Type(nil, nil)\n\t\t\trequire.EqualError(t, err, \"specutil: nil type\")\n\t\t\tspec := dummyType(t, ts)\n\t\t\tstyp, err := registry.Type(spec, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoErrorf(t, err, \"failed formatting: %styp\", err)\n\t\t\tconvert, err := registry.Convert(styp)\n\t\t\trequire.NoError(t, err)\n\t\t\tafter, err := registry.Type(convert, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.EqualValues(t, styp, after)\n\t\t})\n\t}\n}\n\n// TestInputVars runs a test verifying that the driver's exposed Eval function uses\n// input variables properly.\nfunc TestInputVars(t *testing.T, evaluator schemahcl.Evaluator) {\n\th := `\nvariable \"tenant\" {\n\ttype = string\n\tdefault = \"test\"\n}\nschema \"tenant\" {\n\tname = var.tenant\n}\ntable \"users\" {\n\tschema = schema.tenant\n\tcolumn \"id\" {\n\t\ttype = int\n\t}\n\tindex \"user_name\" {\n      unique = true\n      on {\n        column = column.id\n      }\n    }\n}\n`\n\tvar test schema.Realm\n\tp := hclparse.NewParser()\n\t_, diag := p.ParseHCL([]byte(h), \"\")\n\trequire.False(t, diag.HasErrors())\n\terr := evaluator.Eval(p, &test, map[string]cty.Value{\"tenant\": cty.StringVal(\"rotemtam\")})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, \"rotemtam\", test.Schemas[0].Name)\n\trequire.Len(t, test.Schemas[0].Tables, 1)\n}\n\nfunc contains(s string, l []string) bool {\n\tfor i := range l {\n\t\tif s == l[i] {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc dummyType(t *testing.T, ts *schemahcl.TypeSpec) *schemahcl.Type {\n\tspec := &schemahcl.Type{T: ts.T}\n\tfor _, attr := range ts.Attributes {\n\t\tvar a *schemahcl.Attr\n\t\tswitch attr.Kind {\n\t\tcase reflect.Int, reflect.Int64:\n\t\t\ta = schemahcl.IntAttr(attr.Name, 2)\n\t\tcase reflect.String:\n\t\t\ta = schemahcl.StringAttr(attr.Name, \"a\")\n\t\tcase reflect.Slice:\n\t\t\ta = schemahcl.StringsAttr(attr.Name, \"a\", \"b\")\n\t\tcase reflect.Bool:\n\t\t\ta = schemahcl.BoolAttr(attr.Name, false)\n\t\tdefault:\n\t\t\tt.Fatalf(\"unsupported kind: %s\", attr.Kind)\n\t\t}\n\t\tspec.Attrs = append(spec.Attrs, a)\n\t}\n\treturn spec\n}\n"
  },
  {
    "path": "sql/internal/specutil/convert.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage specutil\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlspec\"\n\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\n// List of convert function types.\ntype (\n\tConvertTableFunc       func(*sqlspec.Table, *schema.Schema) (*schema.Table, error)\n\tConvertTableColumnFunc func(*sqlspec.Column, *schema.Table) (*schema.Column, error)\n\tConvertViewFunc        func(*sqlspec.View, *schema.Schema) (*schema.View, error)\n\tConvertViewColumnFunc  func(*sqlspec.Column, *schema.View) (*schema.Column, error)\n\tConvertTypeFunc        func(*sqlspec.Column) (schema.Type, error)\n\tConvertPrimaryKeyFunc  func(*sqlspec.PrimaryKey, *schema.Table) (*schema.Index, error)\n\tConvertIndexFunc       func(*sqlspec.Index, *schema.Table) (*schema.Index, error)\n\tConvertViewIndexFunc   func(*sqlspec.Index, *schema.View) (*schema.Index, error)\n\tConvertCheckFunc       func(*sqlspec.Check) (*schema.Check, error)\n\tConvertFuncFunc        func(*sqlspec.Func, *schema.Schema) (*schema.Func, error)\n\tConvertProcFunc        func(*sqlspec.Func, *schema.Schema) (*schema.Proc, error)\n\tColumnTypeSpecFunc     func(schema.Type) (*sqlspec.Column, error)\n\tTableSpecFunc          func(*schema.Table) (*sqlspec.Table, error)\n\tTableColumnSpecFunc    func(*schema.Column, *schema.Table) (*sqlspec.Column, error)\n\tViewSpecFunc           func(*schema.View) (*sqlspec.View, error)\n\tViewColumnSpecFunc     func(*schema.Column, *schema.View) (*sqlspec.Column, error)\n\tPrimaryKeySpecFunc     func(*schema.Index) (*sqlspec.PrimaryKey, error)\n\tIndexSpecFunc          func(*schema.Index) (*sqlspec.Index, error)\n\tForeignKeySpecFunc     func(*schema.ForeignKey) (*sqlspec.ForeignKey, error)\n\tCheckSpecFunc          func(*schema.Check) *sqlspec.Check\n)\n\ntype (\n\t// ScanDoc represents a scanned HCL document.\n\tScanDoc struct {\n\t\tSchemas      []*sqlspec.Schema\n\t\tTables       []*sqlspec.Table\n\t\tViews        []*sqlspec.View\n\t\tMaterialized []*sqlspec.View\n\t\tFuncs        []*sqlspec.Func\n\t\tProcs        []*sqlspec.Func\n\t\tTriggers     []*sqlspec.Trigger\n\t}\n\n\t// ScanFuncs represents a set of scan functions\n\t// used to convert the HCL document to the Realm.\n\tScanFuncs struct {\n\t\tTable ConvertTableFunc\n\t\tView  ConvertViewFunc\n\t\tFunc  ConvertFuncFunc\n\t\tProc  ConvertProcFunc\n\t\t// Triggers add themselves to the relevant tables/views.\n\t\tTriggers func(*schema.Realm, []*sqlspec.Trigger) error\n\t\t// Objects add themselves to the realm.\n\t\tObjects func(*schema.Realm) error\n\t\t// Optional function to extend the foreign keys.\n\t\tForeignKey func(*sqlspec.ForeignKey, *schema.ForeignKey) error\n\t}\n\n\t// SchemaFuncs represents a set of spec functions\n\t// used to convert the Schema object to an HCL document.\n\tSchemaFuncs struct {\n\t\tTable TableSpecFunc\n\t\tView  ViewSpecFunc\n\t\tFunc  func(*schema.Func) (*sqlspec.Func, error)\n\t\tProc  func(*schema.Proc) (*sqlspec.Func, error)\n\t}\n\t// RefNamer is an interface for objects that can\n\t// return their reference.\n\tRefNamer interface {\n\t\t// Ref returns the reference to the object.\n\t\tRef() *schemahcl.Ref\n\t}\n\t// SpecTypeNamer is an interface for objects that can\n\t// return their spec type and name.\n\tSpecTypeNamer interface {\n\t\tSpecTyper\n\t\t// SpecName returns the spec name of the object.\n\t\tSpecName() string\n\t}\n\t// SpecTyper wraps the SpecType method. It allows objects\n\t// to describe what their spec type is.\n\tSpecTyper interface {\n\t\t// SpecType returns the spec type of the object.\n\t\tSpecType() string\n\t}\n)\n\nconst (\n\ttypeView         = \"view\"\n\ttypeTable        = \"table\"\n\ttypeColumn       = \"column\"\n\ttypeIndex        = \"index\"\n\ttypeSchema       = \"schema\"\n\ttypeMaterialized = \"materialized\"\n\ttypeFunction     = \"function\"\n\ttypeProcedure    = \"procedure\"\n\ttypeTrigger      = \"trigger\"\n)\n\n// typeName returns the type name of the given object.\nfunc typeName(o schema.Object) string {\n\tattrOr := func(n string, attrs []schema.Attr) string {\n\t\tfor _, a := range attrs {\n\t\t\tif t, ok := a.(SpecTyper); ok && t.SpecType() != \"\" {\n\t\t\t\tn = t.SpecType()\n\t\t\t}\n\t\t}\n\t\treturn n\n\t}\n\tswitch o := o.(type) {\n\tcase nil:\n\tcase *schema.Table:\n\t\tif o == nil {\n\t\t\treturn typeTable\n\t\t}\n\t\treturn attrOr(typeTable, o.Attrs)\n\tcase *schema.View:\n\t\tswitch {\n\t\tcase o == nil:\n\t\t\treturn typeView\n\t\tcase o.Materialized():\n\t\t\treturn attrOr(typeMaterialized, o.Attrs)\n\t\tdefault:\n\t\t\treturn attrOr(typeView, o.Attrs)\n\t\t}\n\tcase *schema.Func:\n\t\tif o == nil {\n\t\t\treturn typeFunction\n\t\t}\n\t\treturn attrOr(typeFunction, o.Attrs)\n\tcase *schema.Proc:\n\t\tif o == nil {\n\t\t\treturn typeProcedure\n\t\t}\n\t\treturn attrOr(typeProcedure, o.Attrs)\n\tdefault:\n\t\tif ts, ok := o.(SpecTyper); ok && ts != nil && ts.SpecType() != \"\" {\n\t\t\treturn ts.SpecType()\n\t\t}\n\t}\n\treturn \"object\"\n}\n\n// Scan populates the Realm from the schemas and table specs.\nfunc Scan(r *schema.Realm, doc *ScanDoc, funcs *ScanFuncs) error {\n\tbyName := make(map[string]*schema.Schema)\n\tfor _, s := range doc.Schemas {\n\t\ts1 := schema.New(s.Name)\n\t\tif err := convertCommentFromSpec(s, &s1.Attrs); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tschemahcl.AppendPos(&s1.Attrs, s.Range)\n\t\tr.AddSchemas(s1)\n\t\tbyName[s.Name] = s1\n\t}\n\tvar (\n\t\tfks     = make(map[*schema.Table][]*sqlspec.ForeignKey)\n\t\tdeps    = make(map[schema.Object][]*schemahcl.Ref, len(doc.Views))\n\t\taliases = make(map[string]string)\n\t)\n\tfor _, st := range doc.Tables {\n\t\tname, err := SchemaName(st.Schema)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot extract schema name for table %q: %w\", st.Name, err)\n\t\t}\n\t\ts, ok := byName[name]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"schema %q not found for table %q\", name, st.Name)\n\t\t}\n\t\tt, err := funcs.Table(st, s)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot convert table %q: %w\", st.Name, err)\n\t\t}\n\t\tif tn := typeName(t); tn != typeTable {\n\t\t\taliases[tn] = typeTable\n\t\t}\n\t\tfks[t] = st.ForeignKeys\n\t\ts.AddTables(t)\n\t\tif d, ok := st.Attr(\"depends_on\"); ok {\n\t\t\trefs, err := d.Refs()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"expect list of references for attribute table.%s.depends_on: %w\", st.Name, err)\n\t\t\t}\n\t\t\tdeps[t] = refs\n\t\t}\n\t}\n\t// Link the foreign keys.\n\tfor t, fks := range fks {\n\t\tif err := linkForeignKeys(funcs, t, fks); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, sv := range doc.Views {\n\t\tname, err := SchemaName(sv.Schema)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot extract schema name for view %q: %w\", sv.Name, err)\n\t\t}\n\t\ts, ok := byName[name]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"schema %q not found for view %q\", name, sv.Name)\n\t\t}\n\t\tv, err := funcs.View(sv, s)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot convert view %q: %w\", sv.Name, err)\n\t\t}\n\t\tif tn := typeName(v); tn != typeView {\n\t\t\taliases[tn] = typeView\n\t\t}\n\t\ts.AddViews(v)\n\t\tif d, ok := sv.Attr(\"depends_on\"); ok {\n\t\t\trefs, err := d.Refs()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"expect list of references for attribute view.%s.depends_on: %w\", sv.Name, err)\n\t\t\t}\n\t\t\tdeps[v] = refs\n\t\t}\n\t}\n\tfor _, m := range doc.Materialized {\n\t\tname, err := SchemaName(m.Schema)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot extract schema name for materialized %q: %w\", m.Name, err)\n\t\t}\n\t\ts, ok := byName[name]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"schema %q not found for materialized %q\", name, m.Name)\n\t\t}\n\t\tv, err := funcs.View(m, s)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot convert materialized %q: %w\", m.Name, err)\n\t\t}\n\t\tif tn := typeName(v); tn != typeMaterialized {\n\t\t\taliases[tn] = typeMaterialized\n\t\t}\n\t\ts.AddViews(v.SetMaterialized(true))\n\t\tif d, ok := m.Attr(\"depends_on\"); ok {\n\t\t\trefs, err := d.Refs()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"expect list of references for attribute materialized.%s.depends_on: %w\", m.Name, err)\n\t\t\t}\n\t\t\tdeps[v] = refs\n\t\t}\n\t}\n\tif funcs.Func != nil {\n\t\tfor _, sf := range doc.Funcs {\n\t\t\tname, err := SchemaName(sf.Schema)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"cannot extract schema name for function %q: %w\", sf.Name, err)\n\t\t\t}\n\t\t\ts, ok := byName[name]\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"schema %q not found for function %q\", name, sf.Name)\n\t\t\t}\n\t\t\tf, err := funcs.Func(sf, s)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"cannot convert function %q: %w\", sf.Name, err)\n\t\t\t}\n\t\t\tif tn := typeName(f); tn != typeFunction {\n\t\t\t\taliases[tn] = typeFunction\n\t\t\t}\n\t\t\ts.AddFuncs(f)\n\t\t\tif d, ok := sf.Attr(\"depends_on\"); ok {\n\t\t\t\trefs, err := d.Refs()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"expect list of references for attribute function.%s.depends_on: %w\", f.Name, err)\n\t\t\t\t}\n\t\t\t\tdeps[f] = refs\n\t\t\t}\n\t\t}\n\t}\n\tif funcs.Proc != nil {\n\t\tfor _, sf := range doc.Procs {\n\t\t\tname, err := SchemaName(sf.Schema)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"cannot extract schema name for procedure %q: %w\", sf.Name, err)\n\t\t\t}\n\t\t\ts, ok := byName[name]\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"schema %q not found for procedure %q\", name, sf.Name)\n\t\t\t}\n\t\t\tf, err := funcs.Proc(sf, s)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"cannot convert procedure %q: %w\", sf.Name, err)\n\t\t\t}\n\t\t\tif tn := typeName(f); tn != typeProcedure {\n\t\t\t\taliases[tn] = typeProcedure\n\t\t\t}\n\t\t\ts.AddProcs(f)\n\t\t\tif d, ok := sf.Attr(\"depends_on\"); ok {\n\t\t\t\trefs, err := d.Refs()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"expect list of references for attribute procedure.%s.depends_on: %w\", f.Name, err)\n\t\t\t\t}\n\t\t\t\tdeps[f] = refs\n\t\t\t}\n\t\t}\n\t}\n\tif funcs.Triggers != nil {\n\t\tif err := funcs.Triggers(r, doc.Triggers); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif funcs.Objects != nil {\n\t\tif err := funcs.Objects(r); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor o, refs := range deps {\n\t\tvar err error\n\t\tswitch o := o.(type) {\n\t\tcase *schema.Table:\n\t\t\terr = fromDependsOn(fmt.Sprintf(\"%s.%s\", typeName(o), o.Name), o, o.Schema, refs, aliases)\n\t\tcase *schema.View:\n\t\t\terr = fromDependsOn(fmt.Sprintf(\"%s.%s\", typeName(o), o.Name), o, o.Schema, refs, aliases)\n\t\tcase *schema.Func:\n\t\t\terr = fromDependsOn(fmt.Sprintf(\"%s.%s\", typeName(o), o.Name), o, o.Schema, refs, aliases)\n\t\tcase *schema.Proc:\n\t\t\terr = fromDependsOn(fmt.Sprintf(\"%s.%s\", typeName(o), o.Name), o, o.Schema, refs, aliases)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Table converts a sqlspec.Table to a schema.Table. Table conversion is done without converting\n// ForeignKeySpecs into ForeignKeys, as the target tables do not necessarily exist in the schema\n// at this point. Instead, the linking is done by the Schema function.\nfunc Table(spec *sqlspec.Table, parent *schema.Schema, convertColumn ConvertTableColumnFunc,\n\tconvertPK ConvertPrimaryKeyFunc, convertIndex ConvertIndexFunc, convertCheck ConvertCheckFunc) (*schema.Table, error) {\n\tt := &schema.Table{\n\t\tName:   spec.Name,\n\t\tSchema: parent,\n\t}\n\tschemahcl.AppendPos(&t.Attrs, spec.Range)\n\tfor _, cs := range spec.Columns {\n\t\tc, err := convertColumn(cs, t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschemahcl.AppendPos(&c.Attrs, cs.Range)\n\t\tt.AddColumns(c)\n\t}\n\tif spec.PrimaryKey != nil {\n\t\tpk, err := convertPK(spec.PrimaryKey, t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschemahcl.AppendPos(&pk.Attrs, spec.PrimaryKey.Range)\n\t\tt.SetPrimaryKey(pk)\n\t}\n\tfor _, idx := range spec.Indexes {\n\t\ti, err := convertIndex(idx, t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschemahcl.AppendPos(&i.Attrs, idx.Range)\n\t\tt.AddIndexes(i)\n\t}\n\tfor _, c := range spec.Checks {\n\t\tck, err := convertCheck(c)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschemahcl.AppendPos(&ck.Attrs, c.Range)\n\t\tt.AddChecks(ck)\n\t}\n\tif err := convertCommentFromSpec(spec, &t.Attrs); err != nil {\n\t\treturn nil, err\n\t}\n\treturn t, nil\n}\n\n// View converts a sqlspec.View to a schema.View.\nfunc View(spec *sqlspec.View, parent *schema.Schema, convertC ConvertViewColumnFunc, convertI ConvertViewIndexFunc) (*schema.View, error) {\n\tas, ok := spec.Extra.Attr(\"as\")\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"missing 'as' definition for view %q\", spec.Name)\n\t}\n\tdef, err := as.String()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"expect string definition for attribute view.%s.as: %w\", spec.Name, err)\n\t}\n\tv := schema.NewView(spec.Name, def).SetSchema(parent)\n\tschemahcl.AppendPos(&v.Attrs, spec.Range)\n\tfor _, cs := range spec.Columns {\n\t\tc, err := convertC(cs, v)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschemahcl.AppendPos(&c.Attrs, cs.Range)\n\t\tv.AddColumns(c)\n\t}\n\tfor _, idx := range spec.Indexes {\n\t\ti, err := convertI(idx, v)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschemahcl.AppendPos(&i.Attrs, idx.Range)\n\t\tv.AddIndexes(i)\n\t}\n\tif err := convertCommentFromSpec(spec, &v.Attrs); err != nil {\n\t\treturn nil, err\n\t}\n\tif c, ok := spec.Extra.Attr(\"check_option\"); ok {\n\t\to, err := c.String()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"expect string definition for attribute view.%s.check_option: %w\", spec.Name, err)\n\t\t}\n\t\tv.SetCheckOption(o)\n\t}\n\treturn v, nil\n}\n\n// Column converts a sqlspec.Column into a schema.Column.\nfunc Column(spec *sqlspec.Column, conv ConvertTypeFunc) (*schema.Column, error) {\n\tout := &schema.Column{\n\t\tName: spec.Name,\n\t\tType: &schema.ColumnType{\n\t\t\tNull: spec.Null,\n\t\t},\n\t}\n\td, err := columnDefault(spec.Remain())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tout.Default = d\n\tct, err := conv(spec)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tout.Type.Type = ct\n\tif err := convertCommentFromSpec(spec, &out.Attrs); err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, err\n}\n\nfunc columnDefault(r *schemahcl.Resource) (schema.Expr, error) {\n\tdefaultA, okA := r.Attr(\"default\")\n\tdefaultR, okR := r.Resource(\"default\")\n\tswitch {\n\tcase okA && okR:\n\t\treturn nil, errors.New(\"both default and default resource are set\")\n\tcase okA:\n\t\tv, err := Default(defaultA.V)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn v, nil\n\tcase okR:\n\t\tvar spec struct {\n\t\t\tName string    `spec:\",name\"`\n\t\t\tAs   cty.Value `spec:\"as\"`\n\t\t}\n\t\tif err := defaultR.As(&spec); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tv, err := Default(spec.As)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &schema.NamedDefault{Name: spec.Name, Expr: v}, nil\n\tdefault:\n\t\treturn nil, nil\n\t}\n}\n\n// Default converts a cty.Value (as defined in the spec) into a schema.Expr.\nfunc Default(d cty.Value) (schema.Expr, error) {\n\tif d.IsNull() {\n\t\treturn nil, nil // no default.\n\t}\n\tvar x schema.Expr\n\tswitch {\n\tcase d.Type() == cty.String:\n\t\tx = &schema.Literal{V: d.AsString()}\n\tcase d.Type() == cty.Number:\n\t\tf := d.AsBigFloat()\n\t\t// If the number is an integer, convert it to an integer.\n\t\tif f.IsInt() {\n\t\t\tx = &schema.Literal{V: f.Text('f', -1)}\n\t\t} else {\n\t\t\tx = &schema.Literal{V: f.String()}\n\t\t}\n\tcase d.Type() == cty.Bool:\n\t\tx = &schema.Literal{V: strconv.FormatBool(d.True())}\n\tcase d.Type().IsCapsuleType():\n\t\traw, ok := d.EncapsulatedValue().(*schemahcl.RawExpr)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"invalid default value %q\", d.Type().FriendlyName())\n\t\t}\n\t\tx = &schema.RawExpr{X: raw.X}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported type for default value: %T\", d)\n\t}\n\treturn x, nil\n}\n\n// Index converts a sqlspec.Index to a schema.Index. The optional arguments allow\n// passing functions for mutating the created index-part (e.g. add attributes).\nfunc Index(spec *sqlspec.Index, parent *schema.Table, partFns ...func(*sqlspec.IndexPart, *schema.IndexPart) error) (*schema.Index, error) {\n\tparts := make([]*schema.IndexPart, 0, len(spec.Columns)+len(spec.Parts))\n\tswitch n, m := len(spec.Columns), len(spec.Parts); {\n\tcase n == 0 && m == 0:\n\t\treturn nil, fmt.Errorf(\"missing definition for index %q\", spec.Name)\n\tcase n > 0 && m > 0:\n\t\treturn nil, fmt.Errorf(`multiple definitions for index %q, use \"columns\" or \"on\"`, spec.Name)\n\tcase n > 0:\n\t\tfor i, c := range spec.Columns {\n\t\t\tc, err := ColumnByRef(parent, c)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tparts = append(parts, &schema.IndexPart{\n\t\t\t\tSeqNo: i,\n\t\t\t\tC:     c,\n\t\t\t})\n\t\t}\n\tcase m > 0:\n\t\tfor i, p := range spec.Parts {\n\t\t\tpart := &schema.IndexPart{SeqNo: i, Desc: p.Desc}\n\t\t\tswitch {\n\t\t\tcase p.Column == nil && p.Expr == \"\":\n\t\t\t\treturn nil, fmt.Errorf(`\"column\" or \"expr\" are required for index %q at position %d`, spec.Name, i)\n\t\t\tcase p.Column != nil && p.Expr != \"\":\n\t\t\t\treturn nil, fmt.Errorf(`cannot use both \"column\" and \"expr\" in index %q at position %d`, spec.Name, i)\n\t\t\tcase p.Expr != \"\":\n\t\t\t\tpart.X = &schema.RawExpr{X: p.Expr}\n\t\t\tcase p.Column != nil:\n\t\t\t\tc, err := ColumnByRef(parent, p.Column)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tpart.C = c\n\t\t\t}\n\t\t\tfor _, f := range partFns {\n\t\t\t\tif err := f(p, part); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t\tparts = append(parts, part)\n\t\t}\n\t}\n\tidx := &schema.Index{\n\t\tName:   spec.Name,\n\t\tUnique: spec.Unique,\n\t\tTable:  parent,\n\t\tParts:  parts,\n\t}\n\tif err := convertCommentFromSpec(spec, &idx.Attrs); err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, p := range idx.Parts {\n\t\tif p.C != nil {\n\t\t\tp.C.AddIndexes(idx)\n\t\t}\n\t}\n\treturn idx, nil\n}\n\n// Check converts a sqlspec.Check to a schema.Check.\nfunc Check(spec *sqlspec.Check) (*schema.Check, error) {\n\treturn &schema.Check{\n\t\tName: spec.Name,\n\t\tExpr: spec.Expr,\n\t}, nil\n}\n\n// PrimaryKey converts a sqlspec.PrimaryKey to a schema.Index.\nfunc PrimaryKey(spec *sqlspec.PrimaryKey, parent *schema.Table) (*schema.Index, error) {\n\tparts := make([]*schema.IndexPart, 0, len(spec.Columns))\n\tfor seqno, c := range spec.Columns {\n\t\tc, err := ColumnByRef(parent, c)\n\t\tif err != nil {\n\t\t\treturn nil, nil\n\t\t}\n\t\tparts = append(parts, &schema.IndexPart{\n\t\t\tSeqNo: seqno,\n\t\t\tC:     c,\n\t\t})\n\t}\n\tpk := &schema.Index{\n\t\tName:  spec.Name,\n\t\tTable: parent,\n\t\tParts: parts,\n\t}\n\tif err := convertCommentFromSpec(spec, &pk.Attrs); err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, p := range pk.Parts {\n\t\tif p.C != nil {\n\t\t\tp.C.AddIndexes(pk)\n\t\t}\n\t}\n\treturn pk, nil\n}\n\n// linkForeignKeys creates the foreign keys defined in the Table's spec by creating references\n// to column in the provided Schema. It is assumed that all tables referenced FK definitions in the spec\n// are reachable from the provided schema or its connected realm.\nfunc linkForeignKeys(funcs *ScanFuncs, tbl *schema.Table, fks []*sqlspec.ForeignKey) error {\n\tfor _, spec := range fks {\n\t\tfk := &schema.ForeignKey{Symbol: spec.Symbol, Table: tbl}\n\t\tschemahcl.AppendPos(&fk.Attrs, spec.Range)\n\t\tif spec.OnUpdate != nil {\n\t\t\tfk.OnUpdate = schema.ReferenceOption(FromVar(spec.OnUpdate.V))\n\t\t}\n\t\tif spec.OnDelete != nil {\n\t\t\tfk.OnDelete = schema.ReferenceOption(FromVar(spec.OnDelete.V))\n\t\t}\n\t\tif n, m := len(spec.Columns), len(spec.RefColumns); n != m {\n\t\t\treturn fmt.Errorf(\"sqlspec: number of referencing and referenced columns do not match for foreign-key %q\", fk.Symbol)\n\t\t}\n\t\tfor _, ref := range spec.Columns {\n\t\t\tc, err := ColumnByRef(tbl, ref)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tfk.Columns = append(fk.Columns, c)\n\t\t}\n\t\tfor i, ref := range spec.RefColumns {\n\t\t\tt, c, err := externalRef(ref, tbl.Schema)\n\t\t\tif isLocalRef(ref) {\n\t\t\t\tt = fk.Table\n\t\t\t\tc, err = ColumnByRef(fk.Table, ref)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif i > 0 && fk.RefTable != t {\n\t\t\t\treturn fmt.Errorf(\"sqlspec: more than 1 table was referenced for foreign-key %q\", fk.Symbol)\n\t\t\t}\n\t\t\tfk.RefTable = t\n\t\t\tfk.RefColumns = append(fk.RefColumns, c)\n\t\t}\n\t\ttbl.ForeignKeys = append(tbl.ForeignKeys, fk)\n\t\tif funcs.ForeignKey != nil {\n\t\t\tif err := funcs.ForeignKey(spec, fk); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// FromSchema converts a schema.Schema into sqlspec.Schema and []sqlspec.Table.\nfunc FromSchema(s *schema.Schema, funcs *SchemaFuncs) (*SchemaSpec, error) {\n\tspec := &SchemaSpec{\n\t\tSchema: &sqlspec.Schema{\n\t\t\tName: s.Name,\n\t\t},\n\t\tTables:       make([]*sqlspec.Table, 0, len(s.Tables)),\n\t\tViews:        make([]*sqlspec.View, 0, len(s.Views)),\n\t\tMaterialized: make([]*sqlspec.View, 0, len(s.Views)),\n\t}\n\tfor _, t := range s.Tables {\n\t\ttable, err := funcs.Table(t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif s.Name != \"\" {\n\t\t\ttable.Schema = SchemaRef(s.Name)\n\t\t}\n\t\tspec.Tables = append(spec.Tables, table)\n\t\tspec.Triggers = append(spec.Triggers, t.Triggers...)\n\t}\n\tfor _, v := range s.Views {\n\t\tview, err := funcs.View(v)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif s.Name != \"\" {\n\t\t\tview.Schema = SchemaRef(s.Name)\n\t\t}\n\t\tif v.Materialized() {\n\t\t\tspec.Materialized = append(spec.Materialized, view)\n\t\t} else {\n\t\t\tspec.Views = append(spec.Views, view)\n\t\t}\n\t\tspec.Triggers = append(spec.Triggers, v.Triggers...)\n\t}\n\tif funcs.Func != nil {\n\t\tfor _, f := range s.Funcs {\n\t\t\tfn, err := funcs.Func(f)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif s.Name != \"\" {\n\t\t\t\tfn.Schema = SchemaRef(s.Name)\n\t\t\t}\n\t\t\tspec.Funcs = append(spec.Funcs, fn)\n\t\t}\n\t}\n\tif funcs.Proc != nil {\n\t\tfor _, p := range s.Procs {\n\t\t\tpr, err := funcs.Proc(p)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif s.Name != \"\" {\n\t\t\t\tpr.Schema = SchemaRef(s.Name)\n\t\t\t}\n\t\t\tspec.Procs = append(spec.Procs, pr)\n\t\t}\n\t}\n\tconvertCommentFromSchema(s.Attrs, &spec.Schema.Extra.Attrs)\n\treturn spec, nil\n}\n\n// FromTable converts a schema.Table to a sqlspec.Table.\nfunc FromTable(t *schema.Table, colFn TableColumnSpecFunc, pkFn PrimaryKeySpecFunc, idxFn IndexSpecFunc,\n\tfkFn ForeignKeySpecFunc, ckFn CheckSpecFunc) (*sqlspec.Table, error) {\n\tspec := &sqlspec.Table{\n\t\tName: t.Name,\n\t}\n\tfor _, c := range t.Columns {\n\t\tcol, err := colFn(c, t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tspec.Columns = append(spec.Columns, col)\n\t}\n\tif t.PrimaryKey != nil {\n\t\tpk, err := pkFn(t.PrimaryKey)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tspec.PrimaryKey = pk\n\t}\n\tfor _, idx := range t.Indexes {\n\t\ti, err := idxFn(idx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tspec.Indexes = append(spec.Indexes, i)\n\t}\n\tfor _, fk := range t.ForeignKeys {\n\t\tf, err := fkFn(fk)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tspec.ForeignKeys = append(spec.ForeignKeys, f)\n\t}\n\tfor _, attr := range t.Attrs {\n\t\tif c, ok := attr.(*schema.Check); ok {\n\t\t\tspec.Checks = append(spec.Checks, ckFn(c))\n\t\t}\n\t}\n\tif deps, ok := dependsOn(t.Schema.Realm, t.Deps); ok {\n\t\t// Embedding a resource push its attributes to the end.\n\t\tspec.Extra.Children = append(spec.Extra.Children, &schemahcl.Resource{Attrs: []*schemahcl.Attr{deps}})\n\t}\n\tconvertCommentFromSchema(t.Attrs, &spec.Extra.Attrs)\n\treturn spec, nil\n}\n\n// FromView converts a schema.View to a sqlspec.View.\nfunc FromView(v *schema.View, colFn ViewColumnSpecFunc, idxFn IndexSpecFunc) (*sqlspec.View, error) {\n\tspec := &sqlspec.View{\n\t\tName: v.Name,\n\t}\n\tfor _, c := range v.Columns {\n\t\tcs, err := colFn(c, v)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tspec.Columns = append(spec.Columns, cs)\n\t}\n\tfor _, idx := range v.Indexes {\n\t\ti, err := idxFn(idx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tspec.Indexes = append(spec.Indexes, i)\n\t}\n\t// In case the view definition is multi-line,\n\t// format it as indented heredoc with two spaces.\n\tas := sqlspec.MightHeredoc(v.Def)\n\tembed := &schemahcl.Resource{\n\t\tAttrs: []*schemahcl.Attr{\n\t\t\tschemahcl.StringAttr(\"as\", as),\n\t\t},\n\t}\n\tif c := (schema.ViewCheckOption{}); sqlx.Has(v.Attrs, &c) {\n\t\tswitch strings.ToUpper(c.V) {\n\t\tcase schema.ViewCheckOptionNone, \"\":\n\t\tcase schema.ViewCheckOptionLocal, schema.ViewCheckOptionCascaded:\n\t\t\tembed.Attrs = append(embed.Attrs, VarAttr(\"check_option\", c.V))\n\t\tdefault:\n\t\t\tembed.Attrs = append(embed.Attrs, schemahcl.StringAttr(\"check_option\", c.V))\n\t\t}\n\t}\n\tif deps, ok := dependsOn(v.Schema.Realm, v.Deps); ok {\n\t\tembed.Attrs = append(embed.Attrs, deps)\n\t}\n\tconvertCommentFromSchema(v.Attrs, &embed.Attrs)\n\tspec.Extra.Children = append(spec.Extra.Children, embed)\n\treturn spec, nil\n}\n\n// dependsOn returns the depends_on attribute for the given objects.\nfunc dependsOn(realm *schema.Realm, objects []schema.Object) (*schemahcl.Attr, bool) {\n\tvar (\n\t\tn2s  = make(map[string][]*schema.Schema)\n\t\tname = func(t schema.Object, n string) string { return typeName(t) + \"/\" + n }\n\t)\n\t// Qualify references if there are objects with the same name.\n\tif realm != nil {\n\t\tfor _, s := range realm.Schemas {\n\t\t\tfor _, t := range s.Tables {\n\t\t\t\tn2s[name(t, t.Name)] = append(n2s[name(t, t.Name)], s)\n\t\t\t}\n\t\t\tfor _, v := range s.Views {\n\t\t\t\tn2s[name(v, v.Name)] = append(n2s[name(v, v.Name)], s)\n\t\t\t}\n\t\t\tfor _, f := range s.Funcs {\n\t\t\t\tif n := name(f, f.Name); !slices.Contains(n2s[n], s) {\n\t\t\t\t\tn2s[n] = append(n2s[n], s) // Count overload once.\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, p := range s.Procs {\n\t\t\t\tif n := name(p, p.Name); !slices.Contains(n2s[n], s) {\n\t\t\t\t\tn2s[n] = append(n2s[n], s) // Count overload once.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tvar (\n\t\trefs = make(map[string]bool, len(objects))\n\t\tdeps = make([]*schemahcl.Ref, 0, len(objects))\n\t)\n\tfor _, o := range objects {\n\t\tpath := make([]string, 0, 2)\n\t\tvar n, s string\n\t\tswitch d := o.(type) {\n\t\tcase *schema.Table:\n\t\t\tn, s = d.Name, d.Schema.Name\n\t\tcase *schema.View:\n\t\t\tn, s = d.Name, d.Schema.Name\n\t\tcase *schema.Func:\n\t\t\tn, s = d.Name, d.Schema.Name\n\t\tcase *schema.Proc:\n\t\t\tn, s = d.Name, d.Schema.Name\n\t\tcase RefNamer:\n\t\t\t// If the object is a reference, add it to the depends_on list.\n\t\t\tdeps = append(deps, d.Ref())\n\t\t\tcontinue\n\t\t}\n\t\tif len(n2s[name(o, n)]) > 1 {\n\t\t\tpath = append(path, s)\n\t\t}\n\t\tif r := schemahcl.BuildRef([]schemahcl.PathIndex{\n\t\t\t{T: typeName(o), V: append(path, n)},\n\t\t}); !refs[r.V] {\n\t\t\trefs[r.V] = true\n\t\t\tdeps = append(deps, r)\n\t\t}\n\t}\n\tif len(deps) > 0 {\n\t\tslices.SortFunc(deps, func(l, r *schemahcl.Ref) int {\n\t\t\treturn strings.Compare(l.V, r.V)\n\t\t})\n\t\treturn schemahcl.RefsAttr(\"depends_on\", deps...), true\n\t}\n\treturn nil, false\n}\n\nfunc fromDependsOn[T interface{ AddDeps(...schema.Object) T }](loc string, t T, ns *schema.Schema, refs []*schemahcl.Ref, aliases map[string]string) error {\n\tfor i, r := range refs {\n\t\tp, err := r.Path()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"extract %s.depends_on references: %w\", loc, err)\n\t\t}\n\t\tif len(p) == 0 {\n\t\t\treturn fmt.Errorf(\"empty reference exists in %s.depends_on[%d]\", loc, i)\n\t\t}\n\t\tq, n, err := RefName(r, p[0].T)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"extract %s name from %s.depends_on[%d]: %w\", p[0].T, loc, i, err)\n\t\t}\n\t\tvar o schema.Object\n\t\tswitch tn := p[0].T; {\n\t\tcase tn == typeTable, aliases[tn] == typeTable:\n\t\t\to, err = findT(ns, q, n, func(s *schema.Schema, name string) (*schema.Table, bool) {\n\t\t\t\tif v, ok := s.Table(name); ok && typeName(v) == tn {\n\t\t\t\t\treturn v, true\n\t\t\t\t}\n\t\t\t\treturn nil, false\n\t\t\t})\n\t\tcase tn == typeView, aliases[tn] == typeView:\n\t\t\to, err = findT(ns, q, n, func(s *schema.Schema, name string) (*schema.View, bool) {\n\t\t\t\tif v, ok := s.View(name); ok && typeName(v) == tn {\n\t\t\t\t\treturn v, true\n\t\t\t\t}\n\t\t\t\treturn nil, false\n\t\t\t})\n\t\tcase tn == typeMaterialized, aliases[tn] == typeMaterialized:\n\t\t\to, err = findT(ns, q, n, func(s *schema.Schema, name string) (*schema.View, bool) {\n\t\t\t\tif v, ok := s.Materialized(name); ok && typeName(v) == tn {\n\t\t\t\t\treturn v, true\n\t\t\t\t}\n\t\t\t\treturn nil, false\n\t\t\t})\n\t\tcase tn == typeFunction, aliases[tn] == typeFunction:\n\t\t\to, err = findT(ns, q, n, func(s *schema.Schema, name string) (*schema.Func, bool) {\n\t\t\t\tif f, ok := s.Func(name); ok && typeName(f) == tn {\n\t\t\t\t\treturn f, true\n\t\t\t\t}\n\t\t\t\treturn nil, false\n\t\t\t})\n\t\tcase tn == typeProcedure, aliases[tn] == typeProcedure:\n\t\t\to, err = findT(ns, q, n, func(s *schema.Schema, name string) (*schema.Proc, bool) {\n\t\t\t\tif f, ok := s.Proc(name); ok && typeName(f) == tn {\n\t\t\t\t\treturn f, true\n\t\t\t\t}\n\t\t\t\treturn nil, false\n\t\t\t})\n\t\tdefault:\n\t\t\tif o, err = findT(ns, q, n, func(s *schema.Schema, name string) (schema.Object, bool) {\n\t\t\t\treturn s.Object(func(o schema.Object) bool {\n\t\t\t\t\tif o, ok := o.(SpecTypeNamer); ok {\n\t\t\t\t\t\treturn p[0].T == o.SpecType() && name == o.SpecName()\n\t\t\t\t\t}\n\t\t\t\t\treturn false\n\t\t\t\t})\n\t\t\t}); err != nil {\n\t\t\t\tcontinue // Custom objects might be loaded in a different pass.\n\t\t\t}\n\t\t}\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"find %s reference for %s.depends_on[%d]: %w\", p[0].T, loc, i, err)\n\t\t}\n\t\tt.AddDeps(o)\n\t}\n\treturn nil\n}\n\n// FromPrimaryKey converts schema.Index to a sqlspec.PrimaryKey.\nfunc FromPrimaryKey(s *schema.Index) (*sqlspec.PrimaryKey, error) {\n\tc := make([]*schemahcl.Ref, 0, len(s.Parts))\n\tfor _, v := range s.Parts {\n\t\tc = append(c, ColumnRef(v.C.Name))\n\t}\n\treturn &sqlspec.PrimaryKey{\n\t\tColumns: c,\n\t}, nil\n}\n\n// FromColumn converts a *schema.Column into a *sqlspec.Column using the ColumnTypeSpecFunc.\nfunc FromColumn(c *schema.Column, columnTypeSpec ColumnTypeSpecFunc) (*sqlspec.Column, error) {\n\tct, err := columnTypeSpec(c.Type.Type)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tspec := &sqlspec.Column{\n\t\tName: c.Name,\n\t\tType: ct.Type,\n\t\tNull: c.Type.Null,\n\t\tDefaultExtension: schemahcl.DefaultExtension{\n\t\t\tExtra: schemahcl.Resource{Attrs: ct.DefaultExtension.Extra.Attrs},\n\t\t},\n\t}\n\tswitch v := c.Default.(type) {\n\tcase nil:\n\tcase *schema.NamedDefault:\n\t\tlv, err := ColumnDefault(c)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tspec.Extra.Children = append(spec.Extra.Children, &schemahcl.Resource{\n\t\t\tType:  \"default\",\n\t\t\tName:  v.Name,\n\t\t\tAttrs: []*schemahcl.Attr{{K: \"as\", V: lv}},\n\t\t})\n\tdefault:\n\t\tlv, err := ColumnDefault(c)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tspec.Extra.Attrs = slices.Insert(spec.Extra.Attrs, 0, &schemahcl.Attr{K: \"default\", V: lv})\n\t}\n\tconvertCommentFromSchema(c.Attrs, &spec.Extra.Attrs)\n\treturn spec, nil\n}\n\n// FromGenExpr returns the spec for a generated expression.\nfunc FromGenExpr(x schema.GeneratedExpr, t func(string) string) *schemahcl.Resource {\n\treturn &schemahcl.Resource{\n\t\tType: \"as\",\n\t\tAttrs: []*schemahcl.Attr{\n\t\t\tschemahcl.StringAttr(\"expr\", x.Expr),\n\t\t\tVarAttr(\"type\", t(x.Type)),\n\t\t},\n\t}\n}\n\n// ConvertGenExpr converts the \"as\" attribute or the block under the given resource.\nfunc ConvertGenExpr(r *schemahcl.Resource, c *schema.Column, t func(string) string) error {\n\tasA, okA := r.Attr(\"as\")\n\tasR, okR := r.Resource(\"as\")\n\tswitch {\n\tcase okA && okR:\n\t\treturn fmt.Errorf(\"multiple as definitions for column %q\", c.Name)\n\tcase okA:\n\t\texpr, err := asA.String()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tc.Attrs = append(c.Attrs, &schema.GeneratedExpr{\n\t\t\tType: t(\"\"), // default type.\n\t\t\tExpr: expr,\n\t\t})\n\tcase okR:\n\t\tvar spec struct {\n\t\t\tExpr string `spec:\"expr\"`\n\t\t\tType string `spec:\"type\"`\n\t\t}\n\t\tif err := asR.As(&spec); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tc.Attrs = append(c.Attrs, &schema.GeneratedExpr{\n\t\t\tExpr: spec.Expr,\n\t\t\tType: t(spec.Type),\n\t\t})\n\t}\n\treturn nil\n}\n\n// ColumnDefault converts the column default into cty.Value.\nfunc ColumnDefault(c *schema.Column) (cty.Value, error) {\n\tvar textlike bool\n\tif c.Type != nil {\n\t\tswitch c.Type.Type.(type) {\n\t\tcase *schema.StringType, *schema.EnumType:\n\t\t\ttextlike = true\n\t\t}\n\t}\n\tswitch x := schema.UnderlyingExpr(c.Default).(type) {\n\tcase nil:\n\t\treturn cty.NilVal, nil\n\tcase *schema.RawExpr:\n\t\treturn schemahcl.RawExprValue(&schemahcl.RawExpr{X: x.X}), nil\n\tcase *schema.Literal:\n\t\tswitch {\n\t\tcase oneOfPrefix(x.V, \"0x\", \"0X\", \"0b\", \"0B\", \"b'\", \"B'\", \"x'\", \"X'\"):\n\t\t\treturn schemahcl.RawExprValue(&schemahcl.RawExpr{X: x.V}), nil\n\t\tcase sqlx.IsQuoted(x.V, '\\'', '\"'):\n\t\t\t// Normalize single quotes to double quotes.\n\t\t\ts, err := sqlx.Unquote(x.V)\n\t\t\tif err != nil {\n\t\t\t\treturn cty.NilVal, err\n\t\t\t}\n\t\t\treturn cty.StringVal(s), nil\n\t\tcase strings.ToLower(x.V) == \"true\", strings.ToLower(x.V) == \"false\":\n\t\t\treturn cty.BoolVal(strings.ToLower(x.V) == \"true\"), nil\n\t\tcase sqlx.IsLiteralNumber(x.V) && !textlike:\n\t\t\tif strings.Contains(x.V, \".\") {\n\t\t\t\tf, err := strconv.ParseFloat(x.V, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn cty.NilVal, err\n\t\t\t\t}\n\t\t\t\treturn cty.NumberFloatVal(f), nil\n\t\t\t}\n\t\t\tswitch i, err := strconv.ParseInt(x.V, 10, 64); {\n\t\t\tcase errors.Is(err, strconv.ErrRange):\n\t\t\t\tu, err := strconv.ParseUint(x.V, 10, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn cty.NilVal, err\n\t\t\t\t}\n\t\t\t\treturn cty.NumberUIntVal(u), nil\n\t\t\tcase err != nil:\n\t\t\t\treturn cty.NilVal, err\n\t\t\tdefault:\n\t\t\t\treturn cty.NumberIntVal(i), nil\n\t\t\t}\n\t\tdefault:\n\t\t\t// Literal values (non-expressions) are returned as strings.\n\t\t\treturn cty.StringVal(x.V), nil\n\t\t}\n\tdefault:\n\t\treturn cty.NilVal, fmt.Errorf(\"converting expr %T to literal value for column %s\", x, c.Name)\n\t}\n}\n\n// FromIndex converts schema.Index to sqlspec.Index.\nfunc FromIndex(idx *schema.Index, partFns ...func(*schema.Index, *schema.IndexPart, *sqlspec.IndexPart) error) (*sqlspec.Index, error) {\n\tspec := &sqlspec.Index{Name: idx.Name, Unique: idx.Unique}\n\tconvertCommentFromSchema(idx.Attrs, &spec.Extra.Attrs)\n\tspec.Parts = make([]*sqlspec.IndexPart, len(idx.Parts))\n\tfor i, p := range idx.Parts {\n\t\tpart := &sqlspec.IndexPart{Desc: p.Desc}\n\t\tswitch {\n\t\tcase p.C == nil && p.X == nil:\n\t\t\treturn nil, fmt.Errorf(\"missing column or expression for key part of index %q\", idx.Name)\n\t\tcase p.C != nil && p.X != nil:\n\t\t\treturn nil, fmt.Errorf(\"multiple key part definitions for index %q\", idx.Name)\n\t\tcase p.C != nil:\n\t\t\tpart.Column = ColumnRef(p.C.Name)\n\t\tcase p.X != nil:\n\t\t\tx, ok := p.X.(*schema.RawExpr)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"unexpected expression %T for index %q\", p.X, idx.Name)\n\t\t\t}\n\t\t\tpart.Expr = x.X\n\t\t}\n\t\tfor _, f := range partFns {\n\t\t\tif err := f(idx, p, part); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tspec.Parts[i] = part\n\t}\n\tif parts, ok := columnsOnly(spec.Parts); ok {\n\t\tspec.Parts = nil\n\t\tspec.Columns = parts\n\t\treturn spec, nil\n\t}\n\treturn spec, nil\n}\n\nfunc columnsOnly(parts []*sqlspec.IndexPart) ([]*schemahcl.Ref, bool) {\n\tcolumns := make([]*schemahcl.Ref, len(parts))\n\tfor i, p := range parts {\n\t\tif p.Desc || p.Column == nil || len(p.Extra.Attrs) != 0 {\n\t\t\treturn nil, false\n\t\t}\n\t\tcolumns[i] = p.Column\n\t}\n\treturn columns, true\n}\n\n// FromForeignKey converts schema.ForeignKey to sqlspec.ForeignKey.\nfunc FromForeignKey(s *schema.ForeignKey) (*sqlspec.ForeignKey, error) {\n\tc := make([]*schemahcl.Ref, 0, len(s.Columns))\n\tfor _, v := range s.Columns {\n\t\tc = append(c, ColumnRef(v.Name))\n\t}\n\tr := make([]*schemahcl.Ref, 0, len(s.RefColumns))\n\tfor _, v := range s.RefColumns {\n\t\tref := ColumnRef(v.Name)\n\t\tif s.Table != s.RefTable {\n\t\t\tref = ExternalColumnRef(v.Name, s.RefTable.Name)\n\t\t}\n\t\tr = append(r, ref)\n\t}\n\tfk := &sqlspec.ForeignKey{\n\t\tSymbol:     s.Symbol,\n\t\tColumns:    c,\n\t\tRefColumns: r,\n\t}\n\tif s.OnUpdate != \"\" {\n\t\tfk.OnUpdate = &schemahcl.Ref{V: Var(string(s.OnUpdate))}\n\t}\n\tif s.OnDelete != \"\" {\n\t\tfk.OnDelete = &schemahcl.Ref{V: Var(string(s.OnDelete))}\n\t}\n\treturn fk, nil\n}\n\n// FromCheck converts schema.Check to sqlspec.Check.\nfunc FromCheck(s *schema.Check) *sqlspec.Check {\n\treturn &sqlspec.Check{\n\t\tName: s.Name,\n\t\tExpr: s.Expr,\n\t}\n}\n\n// SchemaName returns the name from a ref to a schema.\nfunc SchemaName(ref *schemahcl.Ref) (string, error) {\n\tvs, err := ref.ByType(typeSchema)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif len(vs) != 1 {\n\t\treturn \"\", fmt.Errorf(\"expected 1 schema ref, got %d\", len(vs))\n\t}\n\treturn vs[0], nil\n}\n\n// ColumnByRef returns a column from the table by its reference.\nfunc ColumnByRef(tv interface {\n\tColumn(string) (*schema.Column, bool)\n}, ref *schemahcl.Ref) (*schema.Column, error) {\n\tvs, err := ref.ByType(typeColumn)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(vs) != 1 {\n\t\treturn nil, fmt.Errorf(\"expected 1 column ref, got %d\", len(vs))\n\t}\n\tif c, ok := tv.Column(vs[0]); ok {\n\t\treturn c, nil\n\t}\n\tswitch tv := tv.(type) {\n\tcase *schema.Table:\n\t\treturn nil, fmt.Errorf(\"column %q was not found in table %s\", vs[0], tv.Name)\n\tcase *schema.View:\n\t\treturn nil, fmt.Errorf(\"column %q was not found in view %s\", vs[0], tv.Name)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"column %q was not found in %T\", vs[0], tv)\n\t}\n}\n\n// IndexByRef returns a index from the table/view by its reference.\nfunc IndexByRef(tv interface {\n\tIndex(string) (*schema.Index, bool)\n}, ref *schemahcl.Ref) (*schema.Index, error) {\n\tvs, err := ref.ByType(typeIndex)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(vs) != 1 {\n\t\treturn nil, fmt.Errorf(\"expected 1 index ref, got %d\", len(vs))\n\t}\n\tif c, ok := tv.Index(vs[0]); ok {\n\t\treturn c, nil\n\t}\n\tswitch tv := tv.(type) {\n\tcase *schema.Table:\n\t\treturn nil, fmt.Errorf(\"index %q was not found in table %s\", vs[0], tv.Name)\n\tcase *schema.View:\n\t\treturn nil, fmt.Errorf(\"index %q was not found in view %s\", vs[0], tv.Name)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"index %q was not found in %T\", vs[0], tv)\n\t}\n}\n\nfunc externalRef(ref *schemahcl.Ref, sch *schema.Schema) (*schema.Table, *schema.Column, error) {\n\tqualifier, name, err := TableName(ref)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tt, err := findT(sch, qualifier, name, func(s *schema.Schema, name string) (*schema.Table, bool) {\n\t\treturn s.Table(name)\n\t})\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tc, err := ColumnByRef(t, ref)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn t, c, nil\n}\n\n// findT finds the table/view referenced by ref in the provided schema. If the table/view\n// is not in the provided schema.Schema other schemas in the connected schema.Realm are\n// searched as well.\nfunc findT[T schema.Object](sch *schema.Schema, qualifier, name string, findT func(*schema.Schema, string) (T, bool)) (t T, err error) {\n\tvar (\n\t\tmatches []T              // Found references.\n\t\tschemas []*schema.Schema // Schemas to search.\n\t)\n\tswitch {\n\tcase sch.Realm == nil || qualifier == sch.Name:\n\t\tschemas = []*schema.Schema{sch}\n\tcase qualifier == \"\":\n\t\tschemas = sch.Realm.Schemas\n\tdefault:\n\t\ts, ok := sch.Realm.Schema(qualifier)\n\t\tif ok {\n\t\t\tschemas = []*schema.Schema{s}\n\t\t}\n\t}\n\tfor _, s := range schemas {\n\t\tt, ok := findT(s, name)\n\t\tif ok {\n\t\t\tmatches = append(matches, t)\n\t\t}\n\t}\n\tswitch len(matches) {\n\tcase 1:\n\t\treturn matches[0], nil\n\tcase 0:\n\t\terr = fmt.Errorf(\"referenced %s %q not found\", typeName(t), name)\n\tdefault:\n\t\terr = fmt.Errorf(\"multiple reference %ss found for %q\", typeName(t), name)\n\t}\n\treturn\n}\n\n// TableName returns the qualifier and name from a reference to a table.\nfunc TableName(ref *schemahcl.Ref) (string, string, error) {\n\treturn RefName(ref, typeTable)\n}\n\n// RefName returns the qualifier and name from a reference.\nfunc RefName(ref *schemahcl.Ref, typeName string) (qualifier, name string, err error) {\n\tvs, err := ref.ByType(typeName)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tswitch len(vs) {\n\tcase 1:\n\t\tname = vs[0]\n\tcase 2:\n\t\tqualifier, name = vs[0], vs[1]\n\tdefault:\n\t\treturn \"\", \"\", fmt.Errorf(\"sqlspec: unexpected number of references in %q\", vs)\n\t}\n\treturn\n}\n\nfunc isLocalRef(r *schemahcl.Ref) bool {\n\treturn strings.HasPrefix(r.V, \"$column\")\n}\n\n// ColumnRef returns the reference of a column by its name.\nfunc ColumnRef(cName string) *schemahcl.Ref {\n\treturn schemahcl.BuildRef([]schemahcl.PathIndex{\n\t\t{T: typeColumn, V: []string{cName}},\n\t})\n}\n\n// IndexRef returns the reference of a index by its name.\nfunc IndexRef(name string) *schemahcl.Ref {\n\treturn schemahcl.BuildRef([]schemahcl.PathIndex{\n\t\t{T: typeIndex, V: []string{name}},\n\t})\n}\n\n// ExternalColumnRef returns the reference of a column by its name and table name.\nfunc ExternalColumnRef(cName, tName string) *schemahcl.Ref {\n\treturn schemahcl.BuildRef([]schemahcl.PathIndex{\n\t\t{T: typeTable, V: []string{tName}},\n\t\t{T: typeColumn, V: []string{cName}},\n\t})\n}\n\n// QualifiedExternalColRef returns the reference of a column by its name and qualified table name.\nfunc QualifiedExternalColRef(cName, tName, sName string) *schemahcl.Ref {\n\treturn schemahcl.BuildRef([]schemahcl.PathIndex{\n\t\t{T: typeTable, V: []string{sName, tName}},\n\t\t{T: typeColumn, V: []string{cName}},\n\t})\n}\n\n// SchemaRef returns the schemahcl.Ref to the schema with the given name.\nfunc SchemaRef(name string) *schemahcl.Ref {\n\treturn schemahcl.BuildRef([]schemahcl.PathIndex{\n\t\t{T: typeSchema, V: []string{name}},\n\t})\n}\n\n// Attrer is the interface that wraps the Attr method.\ntype Attrer interface {\n\tAttr(string) (*schemahcl.Attr, bool)\n}\n\n// convertCommentFromSpec converts a spec comment attribute to a schema element attribute.\nfunc convertCommentFromSpec(spec Attrer, attrs *[]schema.Attr) error {\n\tif c, ok := spec.Attr(\"comment\"); ok {\n\t\ts, err := c.String()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t*attrs = append(*attrs, &schema.Comment{Text: s})\n\t}\n\treturn nil\n}\n\n// convertCommentFromSchema converts a schema element comment attribute to a spec comment attribute.\nfunc convertCommentFromSchema(src []schema.Attr, target *[]*schemahcl.Attr) {\n\tvar c schema.Comment\n\tif sqlx.Has(src, &c) {\n\t\t*target = append(*target, schemahcl.StringAttr(\"comment\", c.Text))\n\t}\n}\n\n// ReferenceVars holds the HCL variables\n// for foreign keys' referential-actions.\nvar ReferenceVars = []string{\n\tVar(string(schema.NoAction)),\n\tVar(string(schema.Restrict)),\n\tVar(string(schema.Cascade)),\n\tVar(string(schema.SetNull)),\n\tVar(string(schema.SetDefault)),\n}\n\n// Var formats a string as variable to make it HCL compatible.\n// The result is simple, replace each space with underscore.\nfunc Var(s string) string { return strings.ReplaceAll(s, \" \", \"_\") }\n\n// FromVar is the inverse function of Var.\nfunc FromVar(s string) string { return strings.ReplaceAll(s, \"_\", \" \") }\n\nfunc oneOfPrefix(s string, ps ...string) bool {\n\tfor _, p := range ps {\n\t\tif strings.HasPrefix(s, p) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "sql/internal/specutil/convert_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage specutil\n\nimport (\n\t\"math\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlspec\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\nfunc TestFromSpec_SchemaName(t *testing.T) {\n\tsc := &schema.Schema{\n\t\tName: \"schema\",\n\t\tTables: []*schema.Table{\n\t\t\t{},\n\t\t},\n\t}\n\tsc.Tables[0].Schema = sc\n\tspec, err := FromSchema(sc, &SchemaFuncs{\n\t\tTable: func(*schema.Table) (*sqlspec.Table, error) {\n\t\t\treturn &sqlspec.Table{}, nil\n\t\t},\n\t\tView: func(*schema.View) (*sqlspec.View, error) {\n\t\t\treturn &sqlspec.View{}, nil\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, sc.Name, spec.Schema.Name)\n\trequire.Equal(t, \"$schema.\"+sc.Name, spec.Tables[0].Schema.V)\n}\n\nfunc TestFromForeignKey(t *testing.T) {\n\ttbl := &schema.Table{\n\t\tName: \"users\",\n\t\tColumns: []*schema.Column{\n\t\t\t{\n\t\t\t\tName: \"id\",\n\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\tT: \"int\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"parent_id\",\n\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\tT: \"int\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfk := &schema.ForeignKey{\n\t\tSymbol:     \"fk\",\n\t\tTable:      tbl,\n\t\tColumns:    tbl.Columns[1:],\n\t\tRefTable:   tbl,\n\t\tRefColumns: tbl.Columns[:1],\n\t\tOnUpdate:   schema.NoAction,\n\t\tOnDelete:   schema.Cascade,\n\t}\n\tkey, err := FromForeignKey(fk)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, &sqlspec.ForeignKey{\n\t\tSymbol: \"fk\",\n\t\tColumns: []*schemahcl.Ref{\n\t\t\t{V: \"$column.parent_id\"},\n\t\t},\n\t\tRefColumns: []*schemahcl.Ref{\n\t\t\t{V: \"$column.id\"},\n\t\t},\n\t\tOnUpdate: &schemahcl.Ref{V: \"NO_ACTION\"},\n\t\tOnDelete: &schemahcl.Ref{V: \"CASCADE\"},\n\t}, key)\n\n\tfk.OnDelete = \"\"\n\tfk.OnUpdate = \"\"\n\tkey, err = FromForeignKey(fk)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, &sqlspec.ForeignKey{\n\t\tSymbol: \"fk\",\n\t\tColumns: []*schemahcl.Ref{\n\t\t\t{V: \"$column.parent_id\"},\n\t\t},\n\t\tRefColumns: []*schemahcl.Ref{\n\t\t\t{V: \"$column.id\"},\n\t\t},\n\t}, key)\n}\n\nfunc TestDefault(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tv cty.Value\n\t\tx string\n\t}{\n\t\t{\n\t\t\tv: cty.NumberUIntVal(1),\n\t\t\tx: \"1\",\n\t\t},\n\t\t{\n\t\t\tv: cty.NumberIntVal(1),\n\t\t\tx: \"1\",\n\t\t},\n\t\t{\n\t\t\tv: cty.NumberFloatVal(1),\n\t\t\tx: \"1\",\n\t\t},\n\t\t{\n\t\t\tv: cty.NumberIntVal(-100),\n\t\t\tx: \"-100\",\n\t\t},\n\t\t{\n\t\t\tv: cty.NumberFloatVal(-100),\n\t\t\tx: \"-100\",\n\t\t},\n\t\t{\n\t\t\tv: cty.NumberUIntVal(math.MaxUint64),\n\t\t\tx: \"18446744073709551615\",\n\t\t},\n\t\t{\n\t\t\tv: cty.NumberIntVal(math.MinInt64),\n\t\t\tx: \"-9223372036854775808\",\n\t\t},\n\t\t{\n\t\t\tv: cty.NumberFloatVal(-1024.1024),\n\t\t\tx: \"-1024.1024\",\n\t\t},\n\t\t{\n\t\t\tv: cty.StringVal(\"{}\"),\n\t\t\tx: \"{}\",\n\t\t},\n\t\t{\n\t\t\tv: cty.StringVal(\"1a.1\"),\n\t\t\tx: \"1a.1\",\n\t\t},\n\t} {\n\t\t// From cty.Value (HCL) to database literal.\n\t\tx, err := Default(tt.v)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, tt.x, x.(*schema.Literal).V)\n\t\t// From database literal to cty.Value (HCL).\n\t\tv, err := ColumnDefault(schema.NewColumn(\"\").SetDefault(&schema.Literal{V: tt.x}))\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, tt.v.Equals(v).True())\n\t}\n}\n\nfunc TestColumnDefault_LiteralNumber(t *testing.T) {\n\tv, err := ColumnDefault(\n\t\tschema.NewColumn(\"\").SetDefault(&schema.Literal{V: \"0\"}),\n\t)\n\trequire.NoError(t, err)\n\trequire.True(t, cty.NumberIntVal(0).Equals(v).True())\n\tv, err = ColumnDefault(\n\t\tschema.NewStringColumn(\"\", \"text\").SetDefault(&schema.Literal{V: \"0\"}),\n\t)\n\trequire.NoError(t, err)\n\trequire.True(t, cty.StringVal(\"0\").Equals(v).True())\n}\n\nfunc TestFromView(t *testing.T) {\n\tspec, err := FromView(&schema.View{\n\t\tName:   \"view\",\n\t\tDef:    \"SELECT * FROM users\\r\\n WHERE c NOT LIKE \\\"\\\\r\\\\n\\\"\",\n\t\tSchema: schema.New(\"public\").SetRealm(schema.NewRealm()),\n\t}, nil, nil)\n\trequire.NoError(t, err)\n\tas, ok := spec.DefaultExtension.Attr(\"as\")\n\trequire.True(t, ok)\n\ts, err := as.String()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"<<-SQL\\n  SELECT * FROM users\\n   WHERE c NOT LIKE \\\"\\\\r\\\\n\\\"\\n  SQL\", s)\n}\n"
  },
  {
    "path": "sql/internal/specutil/spec.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage specutil\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlspec\"\n\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\ntype (\n\t// SchemaSpec is returned by driver convert functions to\n\t// marshal a *schema.Schema into top-level spec objects.\n\tSchemaSpec struct {\n\t\tSchema       *sqlspec.Schema\n\t\tTables       []*sqlspec.Table\n\t\tViews        []*sqlspec.View\n\t\tFuncs        []*sqlspec.Func\n\t\tProcs        []*sqlspec.Func\n\t\tMaterialized []*sqlspec.View\n\t\t// Collected triggers to convert into spec.\n\t\tTriggers []*schema.Trigger\n\t}\n\t// RealmFuncs represents the functions that used\n\t// to convert the schema.Realm into HCL spec document.\n\tRealmFuncs struct {\n\t\tSchema   func(*schema.Schema) (*SchemaSpec, error)\n\t\tTriggers func([]*schema.Trigger, *Doc) ([]*sqlspec.Trigger, error)\n\t}\n\t// Doc represents the common HCL spec document.\n\tDoc struct {\n\t\tTables       []*sqlspec.Table   `spec:\"table\"`\n\t\tViews        []*sqlspec.View    `spec:\"view\"`\n\t\tMaterialized []*sqlspec.View    `spec:\"materialized\"`\n\t\tFuncs        []*sqlspec.Func    `spec:\"function\"`\n\t\tProcs        []*sqlspec.Func    `spec:\"procedure\"`\n\t\tTriggers     []*sqlspec.Trigger `spec:\"trigger\"`\n\t\tSchemas      []*sqlspec.Schema  `spec:\"schema\"`\n\t}\n)\n\n// Marshal marshals v into an Atlas DDL document using a schemahcl.Marshaler. Marshal uses the given\n// schemaSpec function to convert a *schema.Schema into *sqlspec.Schema, []*sqlspec.Table and []*sqlspec.View.\nfunc Marshal(v any, marshaler schemahcl.Marshaler, funcs RealmFuncs) ([]byte, error) {\n\tvar (\n\t\td  = &Doc{}\n\t\tts []*schema.Trigger\n\t)\n\tswitch s := v.(type) {\n\tcase *schema.Schema:\n\t\tspec, err := funcs.Schema(s)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"specutil: failed converting schema to spec: %w\", err)\n\t\t}\n\t\td.Tables = spec.Tables\n\t\td.Views = spec.Views\n\t\td.Materialized = spec.Materialized\n\t\td.Schemas = []*sqlspec.Schema{spec.Schema}\n\t\td.Funcs = spec.Funcs\n\t\td.Procs = spec.Procs\n\t\tts = spec.Triggers\n\tcase *schema.Realm:\n\t\tfor _, s := range s.Schemas {\n\t\t\tspec, err := funcs.Schema(s)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"specutil: failed converting schema to spec: %w\", err)\n\t\t\t}\n\t\t\td.Tables = append(d.Tables, spec.Tables...)\n\t\t\td.Views = append(d.Views, spec.Views...)\n\t\t\td.Materialized = append(d.Materialized, spec.Materialized...)\n\t\t\td.Schemas = append(d.Schemas, spec.Schema)\n\t\t\td.Funcs = append(d.Funcs, spec.Funcs...)\n\t\t\td.Procs = append(d.Procs, spec.Procs...)\n\t\t\tts = append(ts, spec.Triggers...)\n\t\t}\n\t\tif err := QualifyObjects(d.Tables); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := QualifyObjects(d.Views); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := QualifyObjects(d.Materialized); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := QualifyObjects(d.Funcs); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := QualifyObjects(d.Procs); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := QualifyReferences(d.Tables, s); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"specutil: failed marshaling spec. %T is not supported\", v)\n\t}\n\tif funcs.Triggers != nil {\n\t\tspecs, err := funcs.Triggers(ts, d)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\td.Triggers = specs\n\t}\n\treturn marshaler.MarshalSpec(d)\n}\n\n// SchemaObject describes a top-level schema object\n// that might be qualified, e.g. a table or a view.\ntype SchemaObject interface {\n\tLabel() string\n\tQualifierLabel() string\n\tSetQualifier(string)\n\tSchemaRef() *schemahcl.Ref\n}\n\n// QualifyObjects sets the Qualifier field equal to the schema\n// name in any objects with duplicate names in the provided specs.\nfunc QualifyObjects[T SchemaObject](specs []T) error {\n\tvar (\n\t\tschemas = make(map[string]bool, len(specs))\n\t\tbyLabel = make(map[string]map[string][]T, len(specs))\n\t)\n\t// Loop first and qualify schema objects with the same label.\n\t// For example, two tables named \"users\" reside in different\n\t// schemas are converted to: (\"s1\", \"users\") and (\"s2\", \"users\").\n\tfor _, v := range specs {\n\t\tl := v.Label()\n\t\tq, err := SchemaName(v.SchemaRef())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif _, ok := byLabel[l]; !ok {\n\t\t\tbyLabel[l] = make(map[string][]T)\n\t\t}\n\t\tbyLabel[l][q] = append(byLabel[l][q], v)\n\t}\n\tfor _, v := range byLabel {\n\t\t// Multiple objects with the same label on the same\n\t\t// schema are not qualified (repeatable blocks).\n\t\tif len(v) == 1 {\n\t\t\tcontinue\n\t\t}\n\t\tfor q, sv := range v {\n\t\t\tfor _, s := range sv {\n\t\t\t\ts.SetQualifier(q)\n\t\t\t\tschemas[q] = true\n\t\t\t}\n\t\t}\n\t}\n\t// After objects were qualified, they might be conflicted with different\n\t// resources that labeled with the schema name. e.g., (\"s1\", \"users\") and\n\t// (\"s1\"). To resolve this conflict, we qualify these objects as well.\n\tfor _, v := range specs {\n\t\tif v.QualifierLabel() == \"\" && schemas[v.Label()] {\n\t\t\tschemaName, err := SchemaName(v.SchemaRef())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tv.SetQualifier(schemaName)\n\t\t}\n\t}\n\treturn nil\n}\n\n// QualifyReferences qualifies any reference with qualifier.\nfunc QualifyReferences(tableSpecs []*sqlspec.Table, realm *schema.Realm) error {\n\ttype cref struct{ s, t string }\n\tbyRef := make(map[cref]*sqlspec.Table)\n\tfor _, t := range tableSpecs {\n\t\tr := cref{s: t.Qualifier, t: t.Name}\n\t\tif byRef[r] != nil {\n\t\t\treturn fmt.Errorf(\"duplicate references were found for: %v\", r)\n\t\t}\n\t\tbyRef[r] = t\n\t}\n\tfor _, t := range tableSpecs {\n\t\tsname, err := SchemaName(t.Schema)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts1, ok := realm.Schema(sname)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"schema %q was not found in realm\", sname)\n\t\t}\n\t\tt1, ok := s1.Table(t.Name)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"table %q.%q was not found in realm\", sname, t.Name)\n\t\t}\n\t\tfor _, fk := range t.ForeignKeys {\n\t\t\tfk1, ok := t1.ForeignKey(fk.Symbol)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"table %q.%q.%q was not found in realm\", sname, t.Name, fk.Symbol)\n\t\t\t}\n\t\t\tfor i, c := range fk.RefColumns {\n\t\t\t\tif r, ok := byRef[cref{s: fk1.RefTable.Schema.Name, t: fk1.RefTable.Name}]; ok && r.Qualifier != \"\" {\n\t\t\t\t\tfk.RefColumns[i] = QualifiedExternalColRef(fk1.RefColumns[i].Name, r.Name, r.Qualifier)\n\t\t\t\t} else if r, ok := byRef[cref{t: fk1.RefTable.Name}]; ok && r.Qualifier == \"\" {\n\t\t\t\t\tfk.RefColumns[i] = ExternalColumnRef(fk1.RefColumns[i].Name, r.Name)\n\t\t\t\t} else {\n\t\t\t\t\treturn fmt.Errorf(\"missing reference for column %q in %q.%q.%q\", c.V, sname, t.Name, fk.Symbol)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// ObjectRef returns a reference to the object. In case there is more than one object of\n// this type with the same name, the reference will be qualified with the schema name.\nfunc ObjectRef(s *schema.Schema, o SpecTypeNamer) *schemahcl.Ref {\n\ttyp, name := o.SpecType(), o.SpecName()\n\tidx := schemahcl.PathIndex{T: typ, V: []string{name}}\n\tif s != nil && s.Realm != nil && len(s.Realm.Schemas) > 1 && slices.ContainsFunc(s.Realm.Schemas, func(s1 *schema.Schema) bool {\n\t\treturn s1 != s && slices.ContainsFunc(s1.Objects, func(o1 schema.Object) bool {\n\t\t\tif e, ok := o1.(SpecTypeNamer); ok {\n\t\t\t\treturn e.SpecType() == typ && e.SpecName() == name\n\t\t\t}\n\t\t\treturn false\n\t\t})\n\t}) {\n\t\tidx.V = append([]string{s.Name}, idx.V...)\n\t}\n\treturn schemahcl.BuildRef([]schemahcl.PathIndex{idx})\n}\n\n// TableSpecRef returns a reference to the table in the spec. In case there is more than\n// one table with the same name, the reference will be qualified with the schema name.\nfunc TableSpecRef(t *schema.Table) *schemahcl.Ref {\n\ttyp, name := typeTable, t.Name\n\tidx := schemahcl.PathIndex{T: typ, V: []string{name}}\n\tif s := t.Schema; s != nil && s.Realm != nil && len(s.Realm.Schemas) > 1 && slices.ContainsFunc(s.Realm.Schemas, func(s1 *schema.Schema) bool {\n\t\treturn s1 != s && slices.ContainsFunc(s1.Tables, func(t1 *schema.Table) bool {\n\t\t\treturn t1.Name == t.Name\n\t\t})\n\t}) {\n\t\tidx.V = append([]string{s.Name}, idx.V...)\n\t}\n\treturn schemahcl.BuildRef([]schemahcl.PathIndex{idx})\n}\n\n// ViewSpecRef returns a reference to the view in the spec. In case there is more than\n// one view with the same name, the reference will be qualified with the schema name.\nfunc ViewSpecRef(v *schema.View) *schemahcl.Ref {\n\ttyp, name := typeView, v.Name\n\tidx := schemahcl.PathIndex{T: typ, V: []string{name}}\n\tif s := v.Schema; s != nil && s.Realm != nil && len(s.Realm.Schemas) > 1 && slices.ContainsFunc(s.Realm.Schemas, func(s1 *schema.Schema) bool {\n\t\treturn s1 != s && slices.ContainsFunc(s1.Views, func(v1 *schema.View) bool {\n\t\t\treturn v.Name == v1.Name\n\t\t})\n\t}) {\n\t\tidx.V = append([]string{s.Name}, idx.V...)\n\t}\n\treturn schemahcl.BuildRef([]schemahcl.PathIndex{idx})\n}\n\n// HCLBytesFunc returns a helper that evaluates an HCL document from a byte slice instead\n// of from an hclparse.Parser instance.\nfunc HCLBytesFunc(ev schemahcl.Evaluator) func(b []byte, v any, inp map[string]cty.Value) error {\n\treturn func(b []byte, v any, inp map[string]cty.Value) error {\n\t\tparser := hclparse.NewParser()\n\t\tif _, diag := parser.ParseHCL(b, \"\"); diag.HasErrors() {\n\t\t\treturn diag\n\t\t}\n\t\treturn ev.Eval(parser, v, inp)\n\t}\n}\n\n// VarAttr is a helper method for constructing *schemahcl.Attr instances that contain a variable reference.\nfunc VarAttr(k, v string) *schemahcl.Attr {\n\treturn schemahcl.RefAttr(k, &schemahcl.Ref{V: v})\n}\n\n// TypeAttr is a helper method for constructing *schemahcl.Attr instances that contain a type reference.\nfunc TypeAttr(k string, t *schemahcl.Type) *schemahcl.Attr {\n\treturn &schemahcl.Attr{\n\t\tK: k,\n\t\tV: schemahcl.TypeValue(t),\n\t}\n}\n"
  },
  {
    "path": "sql/internal/sqltest/sqltest.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqltest\n\nimport (\n\t\"database/sql/driver\"\n\t\"regexp\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n)\n\n// Rows converts MySQL/PostgreSQL table output to sql.Rows.\n// All row values are parsed as text except the \"nil\" and NULL keywords.\n// For example:\n//\n//\t+-------------+-------------+-------------+----------------+\n//\t| column_name | column_type | is_nullable | column_default |\n//\t+-------------+-------------+-------------+----------------+\n//\t| c1          | float       | YES         | nil            |\n//\t| c2          | int         | YES         |                |\n//\t| c3          | double      | YES         | NULL           |\n//\t+-------------+-------------+-------------+----------------+\nfunc Rows(table string) *sqlmock.Rows {\n\tvar (\n\t\tnc    int\n\t\trows  *sqlmock.Rows\n\t\tlines = strings.Split(table, \"\\n\")\n\t)\n\tfor i := 0; i < len(lines); i++ {\n\t\tline := strings.TrimFunc(lines[i], unicode.IsSpace)\n\t\t// Skip new lines, header and footer.\n\t\tif line == \"\" || strings.IndexAny(line, \"+-\") == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tcolumns := strings.FieldsFunc(line, func(r rune) bool {\n\t\t\treturn r == '|'\n\t\t})\n\t\tfor i, c := range columns {\n\t\t\tcolumns[i] = strings.TrimSpace(c)\n\t\t}\n\t\tif rows == nil {\n\t\t\tnc = len(columns)\n\t\t\trows = sqlmock.NewRows(columns)\n\t\t} else {\n\t\t\tvalues := make([]driver.Value, nc)\n\t\t\tfor i, c := range columns {\n\t\t\t\tswitch c {\n\t\t\t\tcase \"\", \"nil\", \"NULL\":\n\t\t\t\tdefault:\n\t\t\t\t\tvalues[i] = c\n\t\t\t\t}\n\t\t\t}\n\t\t\trows.AddRow(values...)\n\t\t}\n\t}\n\treturn rows\n}\n\n// Escape escapes all regular expression metacharacters in the given query.\nfunc Escape(query string) string {\n\trows := strings.Split(query, \"\\n\")\n\tfor i := range rows {\n\t\trows[i] = strings.TrimPrefix(rows[i], \" \")\n\t}\n\tquery = strings.Join(rows, \" \")\n\treturn strings.TrimSpace(regexp.QuoteMeta(query)) + \"$\"\n}\n"
  },
  {
    "path": "sql/internal/sqlx/dev.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlx\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// DevDriver is a driver that provides additional functionality\n// to interact with the development database.\ntype DevDriver struct {\n\t// A Driver connected to the dev database.\n\tDriver migrate.Driver\n\t// PathObject allows providing a custom function to patch\n\t// objects that hold a schema reference.\n\tPatchObject func(*schema.Schema, schema.Object)\n}\n\n// NormalizeRealm implements the schema.Normalizer interface.\n//\n// The implementation converts schema objects in \"natural form\" (e.g. HCL or DSL)\n// to their \"normal presentation\" in the database, by creating them temporarily in\n// a \"dev database\", and then inspects them from there.\nfunc (d *DevDriver) NormalizeRealm(ctx context.Context, r *schema.Realm) (nr *schema.Realm, err error) {\n\trestore, err := d.Driver.Snapshot(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\tif rerr := restore(ctx); rerr != nil {\n\t\t\tif err != nil {\n\t\t\t\trerr = fmt.Errorf(\"%w: %v\", err, rerr)\n\t\t\t}\n\t\t\terr = rerr\n\t\t}\n\t}()\n\tvar (\n\t\tchanges []schema.Change\n\t\topts    = &schema.InspectRealmOption{\n\t\t\tSchemas: make([]string, 0, len(r.Schemas)),\n\t\t}\n\t)\n\tname2pos := make(key2pos)\n\tfor _, o := range r.Objects {\n\t\tchanges = append(changes, &schema.AddObject{\n\t\t\tO: o,\n\t\t\tExtra: []schema.Clause{\n\t\t\t\t&schema.IfNotExists{},\n\t\t\t},\n\t\t})\n\t\tname2pos.putObject(o)\n\t}\n\tfor _, s := range r.Schemas {\n\t\tk, _ := name2pos.put(s.Attrs, keyS, s.Name)\n\t\topts.Schemas = append(opts.Schemas, s.Name)\n\t\tchanges = append(changes, &schema.AddSchema{\n\t\t\tS: s,\n\t\t\tExtra: []schema.Clause{\n\t\t\t\t&schema.IfNotExists{},\n\t\t\t},\n\t\t})\n\t\tfor _, t := range s.Tables {\n\t\t\tchanges = append(changes, addTableChange(t)...)\n\t\t\t// If the table was loaded with its position,\n\t\t\t// record the position of its children.\n\t\t\tif tk, ok := name2pos.put(t.Attrs, k, keyT, t.Name); ok {\n\t\t\t\tname2pos.putTable(t, tk)\n\t\t\t}\n\t\t}\n\t\tfor _, v := range s.Views {\n\t\t\tchanges = append(changes, addViewChange(v)...)\n\t\t\t// If the view was loaded with its position,\n\t\t\t// record the position of its children.\n\t\t\tif vk, ok := name2pos.put(v.Attrs, k, keyV, v.Name); ok {\n\t\t\t\tname2pos.putView(v, vk)\n\t\t\t}\n\t\t}\n\t\tfor _, o := range s.Objects {\n\t\t\tname2pos.putObject(o, k)\n\t\t\tchanges = append(changes, &schema.AddObject{O: o})\n\t\t}\n\t\tfor _, f := range s.Funcs {\n\t\t\tname2pos.put(f.Attrs, k, keyFn, f.Name)\n\t\t\tchanges = append(changes, &schema.AddFunc{F: f})\n\t\t}\n\t\tfor _, p := range s.Procs {\n\t\t\tname2pos.put(p.Attrs, k, keyPr, p.Name)\n\t\t\tchanges = append(changes, &schema.AddProc{P: p})\n\t\t}\n\t}\n\tif err := d.Driver.ApplyChanges(ctx, changes); err != nil {\n\t\treturn nil, err\n\t}\n\tif nr, err = d.Driver.InspectRealm(ctx, opts); err != nil {\n\t\treturn nil, err\n\t}\n\tif len(name2pos) > 0 {\n\t\tname2pos.patchRealm(nr)\n\t}\n\treturn nr, nil\n}\n\n// NormalizeSchema returns the normal representation of the given database. See NormalizeRealm for more info.\nfunc (d *DevDriver) NormalizeSchema(ctx context.Context, s *schema.Schema) (*schema.Schema, error) {\n\trestore, err := d.Driver.Snapshot(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\tif rerr := restore(ctx); rerr != nil {\n\t\t\tif err != nil {\n\t\t\t\trerr = fmt.Errorf(\"%w: %v\", err, rerr)\n\t\t\t}\n\t\t\terr = rerr\n\t\t}\n\t}()\n\tdev, err := d.Driver.InspectSchema(ctx, \"\", &schema.InspectOptions{\n\t\tMode: schema.InspectSchemas,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Modify dev-schema attributes if needed.\n\tchanges, err := d.Driver.SchemaDiff(\n\t\tschema.New(dev.Name).AddAttrs(dev.Attrs...),\n\t\tschema.New(dev.Name).AddAttrs(s.Attrs...),\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tprevName := s.Name\n\ts.Name = dev.Name\n\tname2pos := make(key2pos)\n\tk, _ := name2pos.put(s.Attrs, keyS, s.Name)\n\tfor _, t := range s.Tables {\n\t\t// If objects are not strongly connected.\n\t\tif t.Schema != s {\n\t\t\tt.Schema = s\n\t\t}\n\t\tfor _, c := range t.Columns {\n\t\t\tif e, ok := c.Type.Type.(*schema.EnumType); ok && e.Schema != s {\n\t\t\t\te.Schema = s\n\t\t\t}\n\t\t}\n\t\tchanges = append(changes, addTableChange(t)...)\n\t\tif tk, ok := name2pos.put(t.Attrs, k, keyT, t.Name); ok {\n\t\t\tname2pos.putTable(t, tk)\n\t\t}\n\t}\n\tfor _, v := range s.Views {\n\t\t// If objects are not strongly connected.\n\t\tif v.Schema != s {\n\t\t\tv.Schema = s\n\t\t}\n\t\tchanges = append(changes, addViewChange(v)...)\n\t\tif vk, ok := name2pos.put(v.Attrs, k, keyV, v.Name); ok {\n\t\t\tname2pos.putView(v, vk)\n\t\t}\n\t}\n\tfor _, o := range s.Objects {\n\t\tif d.PatchObject != nil {\n\t\t\td.PatchObject(s, o)\n\t\t}\n\t\tname2pos.putObject(o, k)\n\t\tchanges = append(changes, &schema.AddObject{O: o})\n\t}\n\tfor _, f := range s.Funcs {\n\t\tname2pos.put(f.Attrs, k, keyFn, f.Name)\n\t\tchanges = append(changes, &schema.AddFunc{F: f})\n\t}\n\tfor _, p := range s.Procs {\n\t\tname2pos.put(p.Attrs, k, keyPr, p.Name)\n\t\tchanges = append(changes, &schema.AddProc{P: p})\n\t}\n\tif err := d.Driver.ApplyChanges(ctx, changes, func(opts *migrate.PlanOptions) {\n\t\tnoQualifier := \"\"\n\t\topts.SchemaQualifier = &noQualifier\n\t\topts.Mode = migrate.PlanModeInPlace\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\tns, err := d.Driver.InspectSchema(ctx, \"\", nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Preserve the original schema name and attributes.\n\tns.Name = prevName\n\tfor _, a := range s.Attrs {\n\t\tschema.ReplaceOrAppend(&ns.Attrs, a)\n\t}\n\tif len(name2pos) > 0 {\n\t\tname2pos.patchSchema(ns)\n\t}\n\treturn ns, err\n}\n\nconst (\n\tkeyS  = \"schema\"\n\tkeyV  = \"view\"\n\tkeyT  = \"table\"\n\tkeyC  = \"column\"\n\tkeyI  = \"index\"\n\tkeyP  = \"pk\"\n\tkeyF  = \"fk\"\n\tkeyK  = \"check\"\n\tkeyTg = \"trigger\"\n\tkeyFn = \"function\"\n\tkeyPr = \"procedure\"\n)\n\ntype key2pos map[string]*schema.Pos\n\nfunc (k key2pos) putTable(t *schema.Table, tk string) {\n\tfor _, c := range t.Columns {\n\t\tk.put(c.Attrs, tk, keyC, c.Name)\n\t}\n\tfor _, i := range t.Indexes {\n\t\tk.put(i.Attrs, tk, keyI, i.Name)\n\t}\n\tfor _, f := range t.ForeignKeys {\n\t\tk.put(f.Attrs, tk, keyF, f.Symbol)\n\t}\n\tfor _, ck := range t.Checks() {\n\t\tk.put(ck.Attrs, tk, keyK, ck.Name)\n\t}\n\tif t.PrimaryKey != nil {\n\t\tk.put(t.PrimaryKey.Attrs, tk, keyP, t.PrimaryKey.Name)\n\t}\n\tfor _, r := range t.Triggers {\n\t\tk.put(r.Attrs, tk, keyTg, r.Name)\n\t}\n}\n\nfunc (k key2pos) putView(v *schema.View, vk string) {\n\tfor _, c := range v.Columns {\n\t\tk.put(c.Attrs, vk, keyC, c.Name)\n\t}\n\tfor _, i := range v.Indexes {\n\t\tk.put(i.Attrs, vk, keyI, i.Name)\n\t}\n\tfor _, r := range v.Triggers {\n\t\tk.put(r.Attrs, vk, keyTg, r.Name)\n\t}\n}\n\nfunc (k key2pos) put(attrs []schema.Attr, typename ...string) (string, bool) {\n\tn := poskey(typename...)\n\tif p := (schema.Pos{}); Has(attrs, &p) {\n\t\tk[n] = &p\n\t\treturn n, true\n\t}\n\treturn n, false\n}\n\nfunc (k key2pos) putObject(o schema.Object, prefix ...string) {\n\tns, ok := o.(schema.SpecTypeNamer)\n\tif !ok {\n\t\treturn\n\t}\n\tt, n := ns.SpecType(), ns.SpecName()\n\tif t == \"\" || n == \"\" {\n\t\treturn\n\t}\n\tnk := poskey(append(prefix, t, n)...)\n\tif ps, ok := o.(schema.PosSetter); ok && ps.Pos() != nil {\n\t\tk[nk] = ps.Pos()\n\t}\n}\n\nfunc (k key2pos) patchRealm(r *schema.Realm) {\n\tk.patchObjects(r.Objects)\n\tfor _, s := range r.Schemas {\n\t\tk.patchSchema(s)\n\t}\n}\n\nfunc (k key2pos) patchObjects(objs []schema.Object, prefix ...string) {\n\tfor _, o := range objs {\n\t\tns, ok := o.(schema.SpecTypeNamer)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tt, n := ns.SpecType(), ns.SpecName()\n\t\tif t == \"\" || n == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tst, ok := o.(schema.PosSetter)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tk.patch(st, append(prefix, t, n)...)\n\t}\n}\n\nfunc (k key2pos) patchSchema(s *schema.Schema) {\n\tks, _ := k.patch(s, keyS, s.Name)\n\tk.patchObjects(s.Objects, ks)\n\tfor _, t := range s.Tables {\n\t\ttk, ok := k.patch(t, ks, keyT, t.Name)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, tr := range t.Triggers {\n\t\t\tk.patch(tr, tk, keyTg, tr.Name)\n\t\t}\n\t\tfor _, c := range t.Columns {\n\t\t\tk.patch(c, tk, keyC, c.Name)\n\t\t}\n\t\tfor _, i := range t.Indexes {\n\t\t\tk.patch(i, tk, keyI, i.Name)\n\t\t}\n\t\tfor _, f := range t.ForeignKeys {\n\t\t\tk.patch(f, tk, keyF, f.Symbol)\n\t\t}\n\t\tfor _, ck := range t.Checks() {\n\t\t\tk.patch(ck, tk, keyK, ck.Name)\n\t\t}\n\t}\n\tfor _, v := range s.Views {\n\t\tvk, ok := k.patch(v, ks, keyV, v.Name)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, tr := range v.Triggers {\n\t\t\tk.patch(tr, vk, keyTg, tr.Name)\n\t\t}\n\t\tfor _, c := range v.Columns {\n\t\t\tk.patch(c, vk, keyC, c.Name)\n\t\t}\n\t\tfor _, i := range v.Indexes {\n\t\t\tk.patch(i, vk, keyI, i.Name)\n\t\t}\n\t}\n\tfor _, f := range s.Funcs {\n\t\tk.patch(f, ks, keyFn, f.Name)\n\t}\n\tfor _, p := range s.Procs {\n\t\tk.patch(p, ks, keyPr, p.Name)\n\t}\n}\n\nfunc (k key2pos) patch(ps schema.PosSetter, typename ...string) (string, bool) {\n\tn := poskey(typename...)\n\tif p, ok := k[n]; ok {\n\t\tps.SetPos(p)\n\t\treturn n, true\n\t}\n\treturn n, false\n}\n\nfunc poskey(typename ...string) string {\n\treturn strings.Join(typename, \".\")\n}\n"
  },
  {
    "path": "sql/internal/sqlx/dev_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlx\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDriver_NormalizeRealm(t *testing.T) {\n\tvar (\n\t\tdrv = &mockDriver{\n\t\t\trealm: schema.NewRealm(schema.New(\"test\").SetCharset(\"utf8mb4\")),\n\t\t}\n\t\tdev = &DevDriver{\n\t\t\tDriver: drv,\n\t\t}\n\t\tr = schema.NewRealm(schema.New(\"test\"))\n\t)\n\tnormal, err := dev.NormalizeRealm(context.Background(), r)\n\trequire.NoError(t, err)\n\trequire.Equal(t, normal, drv.realm)\n\n\trequire.Len(t, drv.schemas, 1)\n\trequire.Len(t, drv.changes, 1, \"expect 1 call for creating the schema\")\n\trequire.Equal(t, &schema.AddSchema{\n\t\tS: r.Schemas[0],\n\t\t// The \"IF NOT EXISTS\" clause is added to make the\n\t\t// operation noop for schema like \"public\" in Postgres.\n\t\tExtra: []schema.Clause{&schema.IfNotExists{}},\n\t}, drv.changes[0])\n\n\t// Retain positions.\n\tr.Schemas[0].\n\t\tAddAttrs(\n\t\t\tschema.NewFilePos(\"schema.hcl\").\n\t\t\t\tSetStart(hcl.Pos{Line: 1, Column: 1, Byte: 1}),\n\t\t).\n\t\tAddTables(\n\t\t\tschema.NewTable(\"t1\").\n\t\t\t\tAddAttrs(\n\t\t\t\t\tschema.NewFilePos(\"schema.hcl\").\n\t\t\t\t\t\tSetStart(hcl.Pos{Line: 2, Column: 2, Byte: 2}),\n\t\t\t\t).\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\").\n\t\t\t\t\t\tAddAttrs(\n\t\t\t\t\t\t\tschema.NewFilePos(\"schema.hcl\").\n\t\t\t\t\t\t\t\tSetStart(hcl.Pos{Line: 3, Column: 3, Byte: 3}),\n\t\t\t\t\t\t),\n\t\t\t\t),\n\t\t)\n\tdrv.realm.Schemas[0].AddTables(\n\t\tschema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t)\n\tnormal, err = dev.NormalizeRealm(context.Background(), r)\n\trequire.NoError(t, err)\n\tp := normal.Schemas[0].Pos()\n\trequire.Equal(t, schema.NewFilePos(\"schema.hcl\").SetStart(hcl.Pos{Line: 1, Column: 1, Byte: 1}), p)\n\tp = normal.Schemas[0].Tables[0].Pos()\n\trequire.Equal(t, schema.NewFilePos(\"schema.hcl\").SetStart(hcl.Pos{Line: 2, Column: 2, Byte: 2}), p)\n\tp = normal.Schemas[0].Tables[0].Columns[0].Pos()\n\trequire.Equal(t, schema.NewFilePos(\"schema.hcl\").SetStart(hcl.Pos{Line: 3, Column: 3, Byte: 3}), p)\n}\n\ntype mockDriver struct {\n\tmigrate.Driver\n\t// Inspect.\n\tschemas []string\n\trealm   *schema.Realm\n\t// Apply.\n\tchanges []schema.Change\n}\n\nfunc (m *mockDriver) InspectRealm(_ context.Context, opts *schema.InspectRealmOption) (*schema.Realm, error) {\n\tm.schemas = append(m.schemas, opts.Schemas...)\n\treturn m.realm, nil\n}\n\nfunc (m *mockDriver) ApplyChanges(_ context.Context, changes []schema.Change, _ ...migrate.PlanOption) error {\n\tm.changes = append(m.changes, changes...)\n\treturn nil\n}\n\nfunc (m *mockDriver) CheckClean(context.Context, *migrate.TableIdent) error {\n\treturn nil\n}\n\nfunc (m *mockDriver) Snapshot(context.Context) (migrate.RestoreFunc, error) {\n\treturn func(context.Context) error { return nil }, nil\n}\n"
  },
  {
    "path": "sql/internal/sqlx/diff.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlx\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"slices\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// NoChange can be returned by DiffDriver methods\n// to indicate that no change is needed.\nvar NoChange = schema.Change(nil)\n\ntype (\n\t// A Diff provides a generic schema.Differ for diffing schema elements.\n\t//\n\t// The DiffDriver is required for supporting database/dialect specific\n\t// diff capabilities, like diffing custom types or attributes.\n\tDiff struct {\n\t\tDiffDriver\n\t}\n\n\t// A DiffDriver wraps all required methods for diffing elements that may\n\t// have database-specific diff logic. See sql/schema/mysql/diff.go for an\n\t// implementation example.\n\tDiffDriver interface {\n\t\t// RealmObjectDiff returns a changeset for migrating realm (database) objects\n\t\t// from one state to the other. For example, adding extensions or users.\n\t\tRealmObjectDiff(from, to *schema.Realm) ([]schema.Change, error)\n\n\t\t// SchemaAttrDiff returns a changeset for migrating schema attributes\n\t\t// from one state to the other. For example, changing schema collation.\n\t\tSchemaAttrDiff(from, to *schema.Schema) []schema.Change\n\n\t\t// SchemaObjectDiff returns a changeset for migrating schema objects from\n\t\t// one state to the other. For example, changing schema custom types.\n\t\tSchemaObjectDiff(from, to *schema.Schema, _ *schema.DiffOptions) ([]schema.Change, error)\n\n\t\t// TableAttrDiff returns a changeset for migrating table attributes from\n\t\t// one state to the other. For example, dropping or adding a `CHECK` constraint.\n\t\tTableAttrDiff(from, to *schema.Table, _ *schema.DiffOptions) ([]schema.Change, error)\n\n\t\t// ViewAttrChanges returns the changes between the two view attributes.\n\t\tViewAttrChanges(from, to *schema.View) []schema.Change\n\n\t\t// ColumnChange returns the schema changes (if any) for migrating one column to the other.\n\t\tColumnChange(fromT *schema.Table, from, to *schema.Column, _ *schema.DiffOptions) (schema.Change, error)\n\n\t\t// IndexAttrChanged reports if the index attributes were changed.\n\t\t// For example, an index type or predicate (for partial indexes).\n\t\tIndexAttrChanged(from, to []schema.Attr) bool\n\n\t\t// IndexPartAttrChanged reports if the part's attributes at position \"i\"\n\t\t// were changed. For example, an index-part collation.\n\t\tIndexPartAttrChanged(from, to *schema.Index, i int) bool\n\n\t\t// IsGeneratedIndexName reports if the index name was generated by the database\n\t\t// for unnamed INDEX or UNIQUE constraints. In such cases, the Differ will look\n\t\t// for unnamed schema.Indexes on the desired state, before tagging the index as\n\t\t// a candidate for deletion.\n\t\tIsGeneratedIndexName(*schema.Table, *schema.Index) bool\n\n\t\t// ReferenceChanged reports if the foreign key referential action was\n\t\t// changed. For example, action was changed from RESTRICT to CASCADE.\n\t\tReferenceChanged(from, to schema.ReferenceOption) bool\n\n\t\t// ForeignKeyAttrChanged reports if any of the foreign-key attributes were changed.\n\t\tForeignKeyAttrChanged(from, to []schema.Attr) bool\n\t}\n\n\t// DropSchemaChanger is an optional interface allows DiffDriver to drop\n\t// schema objects before dropping the schema itself.\n\tDropSchemaChanger interface {\n\t\tDropSchemaChange(*schema.Schema) []schema.Change\n\t}\n\n\t// A Normalizer wraps the Normalize method for normalizing the from and to tables before\n\t// running diffing. The \"from\" usually represents the inspected database state (current),\n\t// and the second represents the desired state.\n\t//\n\t// If the DiffDriver implements the Normalizer interface, TableDiff normalizes its table\n\t// inputs before starting the diff process.\n\tNormalizer interface {\n\t\tNormalize(from, to *schema.Table, opts *schema.DiffOptions) error\n\t}\n\n\t// TableFinder wraps the FindTable method, providing more\n\t// control to the DiffDriver on how tables are matched.\n\tTableFinder interface {\n\t\tFindTable(*schema.Schema, *schema.Table) (*schema.Table, error)\n\t}\n\n\t// ChangesAnnotator is an optional interface allows DiffDriver to annotate\n\t// changes with additional driver-specific attributes before they are returned.\n\tChangesAnnotator interface {\n\t\tAnnotateChanges([]schema.Change, *schema.DiffOptions) ([]schema.Change, error)\n\t}\n\n\t// ProcFuncsDiffer is an optional interface allows DiffDriver to diff\n\t// functions and procedures.\n\tProcFuncsDiffer interface {\n\t\t// ProcFuncsDiff returns a changeset for migrating functions and procedures\n\t\t// from one schema state to the other.\n\t\tProcFuncsDiff(from, to *schema.Schema, opts *schema.DiffOptions) ([]schema.Change, error)\n\t}\n\n\t// TriggerDiffer is an optional interface allows DiffDriver to diff triggers.\n\tTriggerDiffer interface {\n\t\t// TriggerDiff returns a changeset for migrating triggers from\n\t\t// one state to the other. For example, changing action time.\n\t\tTriggerDiff(from, to *schema.Trigger) ([]schema.Change, error)\n\t}\n\n\t// ChangeSupporter wraps the single SupportChange method.\n\tChangeSupporter interface {\n\t\t// SupportChange can be implemented to tell the Differ if they support\n\t\t// a specific change type, or it should avoid suggesting it.\n\t\tSupportChange(schema.Change) bool\n\t}\n)\n\n// RealmDiff implements the schema.Differ for Realm objects and returns a list of changes\n// that need to be applied in order to move a database from the current state to the desired.\nfunc (d *Diff) RealmDiff(from, to *schema.Realm, options ...schema.DiffOption) ([]schema.Change, error) {\n\tvar (\n\t\tchanges schema.Changes\n\t\topts    = schema.NewDiffOptions(options...)\n\t)\n\t// Realm-level objects.\n\tchange, err := d.RealmObjectDiff(from, to)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tchanges = opts.AddOrSkip(changes, change...)\n\t// Drop or modify schema.\n\tfor _, s1 := range from.Schemas {\n\t\ts2, ok := to.Schema(s1.Name)\n\t\tif !ok {\n\t\t\tif ds, ok := d.DiffDriver.(DropSchemaChanger); ok {\n\t\t\t\t// The driver can drop other objects before dropping the schema.\n\t\t\t\tchanges = opts.AddOrSkip(changes, ds.DropSchemaChange(s1)...)\n\t\t\t} else {\n\t\t\t\tchanges = opts.AddOrSkip(changes, &schema.DropSchema{S: s1})\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tchange, err := d.schemaDiff(s1, s2, opts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tchanges = append(changes, change...)\n\t}\n\t// Add schemas.\n\tfor _, s1 := range to.Schemas {\n\t\tif _, ok := from.Schema(s1.Name); ok {\n\t\t\tcontinue\n\t\t}\n\t\tchanges = opts.AddOrSkip(changes, &schema.AddSchema{S: s1})\n\t\tfor _, o := range s1.Objects {\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.AddObject{O: o})\n\t\t}\n\t\tfor _, f := range s1.Funcs {\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.AddFunc{F: f})\n\t\t}\n\t\tfor _, p := range s1.Procs {\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.AddProc{P: p})\n\t\t}\n\t\tfor _, t := range s1.Tables {\n\t\t\tchanges = opts.AddOrSkip(changes, addTableChange(t)...)\n\t\t}\n\t\tfor _, v := range s1.Views {\n\t\t\tchanges = opts.AddOrSkip(changes, addViewChange(v)...)\n\t\t}\n\t}\n\treturn d.mayAnnotate(changes, opts)\n}\n\n// SchemaDiff implements the schema.Differ interface and returns a list of\n// changes that need to be applied in order to move from one state to the other.\nfunc (d *Diff) SchemaDiff(from, to *schema.Schema, options ...schema.DiffOption) ([]schema.Change, error) {\n\topts := schema.NewDiffOptions(options...)\n\tchanges, err := d.schemaDiff(from, to, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn d.mayAnnotate(changes, opts)\n}\n\nfunc (d *Diff) schemaDiff(from, to *schema.Schema, opts *schema.DiffOptions) ([]schema.Change, error) {\n\tif from.Name != to.Name {\n\t\treturn nil, fmt.Errorf(\"mismatched schema names: %q != %q\", from.Name, to.Name)\n\t}\n\tvar changes []schema.Change\n\t// Drop or modify attributes (collations, charset, etc).\n\tif change := d.SchemaAttrDiff(from, to); len(change) > 0 {\n\t\tchanges = opts.AddOrSkip(changes, &schema.ModifySchema{\n\t\t\tS:       to,\n\t\t\tChanges: change,\n\t\t})\n\t}\n\t// Add, drop or modify objects.\n\tchange, err := d.SchemaObjectDiff(from, to, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tchanges = opts.AddOrSkip(changes, change...)\n\n\t// Drop or modify tables.\n\tfor _, t1 := range from.Tables {\n\t\tswitch t2, err := d.findTable(to, t1); {\n\t\tcase schema.IsNotExistError(err):\n\t\t\t// Triggers should be dropped either by the driver or the database.\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.DropTable{T: t1})\n\t\tcase err != nil:\n\t\t\treturn nil, err\n\t\tdefault:\n\t\t\tif change, err := d.tableDiff(t1, t2, opts); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t} else if len(change) > 0 {\n\t\t\t\tchanges = opts.AddOrSkip(changes, &schema.ModifyTable{T: t2, Changes: change})\n\t\t\t}\n\t\t\tif change, err := d.triggerDiff(t1, t2, t1.Triggers, t2.Triggers, opts); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t} else {\n\t\t\t\tchanges = append(changes, change...)\n\t\t\t}\n\t\t}\n\t}\n\tchanges = d.fixRenames(changes)\n\t// Add tables.\n\tfor _, t1 := range to.Tables {\n\t\tswitch _, err := d.findTable(from, t1); {\n\t\tcase schema.IsNotExistError(err):\n\t\t\tchanges = opts.AddOrSkip(changes, addTableChange(t1)...)\n\t\tcase err != nil:\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Drop or modify views.\n\tfor _, v1 := range from.Views {\n\t\tv2, ok := findView(to, v1)\n\t\tif !ok {\n\t\t\t// Changing a view to materialized (and vice versa)\n\t\t\t// generates a drop and add.\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.DropView{V: v1})\n\t\t\tcontinue\n\t\t}\n\t\tif change, err := d.viewDiff(v1, v2, opts); err != nil {\n\t\t\treturn nil, err\n\t\t} else {\n\t\t\tchanges = append(changes, change...)\n\t\t}\n\t\tif change, err := d.triggerDiff(v1, v2, v1.Triggers, v2.Triggers, opts); err != nil {\n\t\t\treturn nil, err\n\t\t} else {\n\t\t\tchanges = append(changes, change...)\n\t\t}\n\t}\n\t// Add views.\n\tfor _, v1 := range to.Views {\n\t\tif _, ok := findView(from, v1); !ok {\n\t\t\tchanges = opts.AddOrSkip(changes, addViewChange(v1)...)\n\t\t}\n\t}\n\t// Add, drop and modify functions and procedures.\n\tif pf, ok := d.DiffDriver.(ProcFuncsDiffer); ok {\n\t\tchange, err := pf.ProcFuncsDiff(from, to, opts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tchanges = append(changes, change...)\n\t}\n\treturn changes, nil\n}\n\n// TableDiff implements the schema.TableDiffer interface and returns a list of\n// changes that need to be applied in order to move from one state to the other.\nfunc (d *Diff) TableDiff(from, to *schema.Table, options ...schema.DiffOption) ([]schema.Change, error) {\n\topts := schema.NewDiffOptions(options...)\n\tif from.Name != to.Name {\n\t\treturn nil, fmt.Errorf(\"mismatched table names: %q != %q\", from.Name, to.Name)\n\t}\n\tchanges, err := d.tableDiff(from, to, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif change, err := d.triggerDiff(from, to, from.Triggers, to.Triggers, opts); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\tchanges = append(changes, change...)\n\t}\n\treturn d.mayAnnotate(changes, opts)\n}\n\n// tableDiff implements the table diffing but skips the table name check.\nfunc (d *Diff) tableDiff(from, to *schema.Table, opts *schema.DiffOptions) ([]schema.Change, error) {\n\t// tableDiff can be called with non-identical\n\t// names without affecting the diff process.\n\tif name := from.Name; name != to.Name {\n\t\tfrom.Name = to.Name\n\t\tdefer func() { from.Name = name }()\n\t}\n\t// Normalizing tables before starting the diff process.\n\tif n, ok := d.DiffDriver.(Normalizer); ok {\n\t\tif err := n.Normalize(from, to, opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tvar changes []schema.Change\n\t// Drop or modify attributes (collations, checks, etc).\n\tchange, err := d.TableAttrDiff(from, to, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tchanges = append(changes, change...)\n\n\t// Drop, add or modify columns.\n\tif change, err = d.columnDiff(from, to, opts); err != nil {\n\t\treturn nil, err\n\t}\n\tchanges = append(changes, change...)\n\n\t// Primary-key and index changes.\n\tchanges = append(changes, d.pkDiff(from, to, opts)...)\n\tif change, err = d.indexDiffT(from, to, opts); err != nil {\n\t\treturn nil, err\n\t}\n\tchanges = append(changes, change...)\n\n\t// Drop or modify foreign-keys.\n\tfor _, fk1 := range from.ForeignKeys {\n\t\tfk2, ok := to.ForeignKey(fk1.Symbol)\n\t\tif !ok {\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.DropForeignKey{F: fk1})\n\t\t\tcontinue\n\t\t}\n\t\tif change := d.fkChange(fk1, fk2); change != schema.NoChange {\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.ModifyForeignKey{\n\t\t\t\tFrom:   fk1,\n\t\t\t\tTo:     fk2,\n\t\t\t\tChange: change,\n\t\t\t})\n\t\t}\n\t}\n\t// Add foreign-keys.\n\tfor _, fk1 := range to.ForeignKeys {\n\t\tif _, ok := from.ForeignKey(fk1.Symbol); !ok {\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.AddForeignKey{F: fk1})\n\t\t}\n\t}\n\treturn changes, nil\n}\n\nfunc (d *Diff) mayAnnotate(changes []schema.Change, opts *schema.DiffOptions) (_ []schema.Change, err error) {\n\tr, ok := d.DiffDriver.(ChangesAnnotator)\n\tif ok {\n\t\tif changes, err = r.AnnotateChanges(changes, opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn changes, nil\n}\n\n// addTableChange returns the changeset for creating the table.\nfunc addTableChange(t *schema.Table) []schema.Change {\n\tchanges := make([]schema.Change, 0, 1+len(t.Triggers))\n\tchanges = append(changes, &schema.AddTable{T: t})\n\tfor _, r := range t.Triggers {\n\t\tchanges = append(changes, &schema.AddTrigger{T: r})\n\t}\n\treturn changes\n}\n\n// addViewChange returns the changeset for creating the view.\nfunc addViewChange(v *schema.View) []schema.Change {\n\tchanges := make([]schema.Change, 0, 1+len(v.Triggers))\n\tchanges = append(changes, &schema.AddView{V: v})\n\tfor _, r := range v.Triggers {\n\t\tchanges = append(changes, &schema.AddTrigger{T: r})\n\t}\n\treturn changes\n}\n\n// columnDiff returns the schema changes (if any) for migrating table columns.\nfunc (d *Diff) columnDiff(from, to *schema.Table, opts *schema.DiffOptions) ([]schema.Change, error) {\n\tvar all []schema.Change\n\t// Drop or modify columns.\n\tfor _, c1 := range from.Columns {\n\t\tc2, ok := to.Column(c1.Name)\n\t\tif !ok {\n\t\t\tall = append(all, &schema.DropColumn{C: c1})\n\t\t\tcontinue\n\t\t}\n\t\tchange, err := d.ColumnChange(from, c1, c2, opts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif change != NoChange {\n\t\t\tall = append(all, change)\n\t\t}\n\t}\n\t// Add columns.\n\tfor _, c1 := range to.Columns {\n\t\tif _, ok := from.Column(c1.Name); !ok {\n\t\t\tall = append(all, &schema.AddColumn{\n\t\t\t\tC: c1,\n\t\t\t})\n\t\t}\n\t}\n\tvar (\n\t\terr     error\n\t\tchanges = make([]schema.Change, 0, len(all))\n\t)\n\tif all, err = d.askForColumns(from, all, opts); err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, c := range all {\n\t\tchanges = opts.AddOrSkip(changes, c)\n\t}\n\treturn changes, nil\n}\n\n// pkDiff returns the schema changes (if any) for migrating table\n// primary-key from current state to the desired state.\nfunc (d *Diff) pkDiff(from, to *schema.Table, opts *schema.DiffOptions) (changes []schema.Change) {\n\tswitch pk1, pk2 := from.PrimaryKey, to.PrimaryKey; {\n\tcase pk1 == nil && pk2 != nil:\n\t\tchanges = opts.AddOrSkip(changes, &schema.AddPrimaryKey{P: pk2})\n\tcase pk1 != nil && pk2 == nil:\n\t\tchanges = opts.AddOrSkip(changes, &schema.DropPrimaryKey{P: pk1})\n\tcase pk1 != nil:\n\t\tchange := d.indexChange(pk1, pk2)\n\t\tchange &= ^schema.ChangeUnique\n\t\tswitch c, ok := d.DiffDriver.(ChangeSupporter); {\n\t\tcase change != schema.NoChange:\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.ModifyPrimaryKey{\n\t\t\t\tFrom: pk1, To: pk2, Change: change,\n\t\t\t})\n\t\tcase (!ok || c.SupportChange((*schema.RenameConstraint)(nil))) &&\n\t\t\tpk1.Name != \"\" && pk2.Name != \"\" && pk1.Name != pk2.Name:\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.RenameConstraint{\n\t\t\t\tFrom: pk1, To: pk2,\n\t\t\t})\n\t\t}\n\t}\n\treturn\n}\n\n// indexDiffT returns the schema changes (if any) for migrating table\n// indexes from current state to the desired state.\nfunc (d *Diff) indexDiffT(from, to *schema.Table, opts *schema.DiffOptions) ([]schema.Change, error) {\n\tvar (\n\t\tall    []schema.Change\n\t\texists = make(map[*schema.Index]bool)\n\t)\n\t// Drop or modify indexes.\n\tfor _, idx1 := range from.Indexes {\n\t\tidx2, ok := to.Index(idx1.Name)\n\t\t// Found directly.\n\t\tif ok {\n\t\t\tif change := d.indexChange(idx1, idx2); change != schema.NoChange {\n\t\t\t\tall = append(all, &schema.ModifyIndex{\n\t\t\t\t\tFrom:   idx1,\n\t\t\t\t\tTo:     idx2,\n\t\t\t\t\tChange: change,\n\t\t\t\t})\n\t\t\t}\n\t\t\texists[idx2] = true\n\t\t\tcontinue\n\t\t}\n\t\t// Found indirectly.\n\t\tif d.IsGeneratedIndexName(from, idx1) {\n\t\t\tif idx2, ok := d.similarUnnamedIndex(to, idx1); ok {\n\t\t\t\texists[idx2] = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\t// Not found.\n\t\tall = append(all, &schema.DropIndex{I: idx1})\n\t}\n\t// Add indexes.\n\tfor _, idx := range to.Indexes {\n\t\tif exists[idx] {\n\t\t\tcontinue\n\t\t}\n\t\tif _, ok := from.Index(idx.Name); !ok {\n\t\t\tall = append(all, &schema.AddIndex{I: idx})\n\t\t}\n\t}\n\tvar (\n\t\terr     error\n\t\tchanges = make([]schema.Change, 0, len(all))\n\t)\n\tif all, err = d.askForIndexes(from.Name, all, opts); err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, c := range all {\n\t\tchanges = opts.AddOrSkip(changes, c)\n\t}\n\treturn changes, nil\n}\n\n// viewDiff returns the schema changes (if any) for migrating view from\n// current state to the desired state.\nfunc (d *Diff) viewDiff(from, to *schema.View, opts *schema.DiffOptions) ([]schema.Change, error) {\n\tc1, err := d.indexDiffV(from, to, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc2, err := d.columnDiffV(from, to, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar changes []schema.Change\n\tif vs := append(d.ViewAttrChanges(from, to), append(c1, c2...)...); len(vs) > 0 || d.viewDefChanged(from, to) {\n\t\tchanges = opts.AddOrSkip(changes, &schema.ModifyView{From: from, To: to, Changes: vs})\n\t}\n\treturn changes, nil\n}\n\n// viewDefChanged checks if the view definition has changed.\n// It allows the DiffDriver to override the default implementation.\nfunc (d *Diff) viewDefChanged(v1 *schema.View, v2 *schema.View) bool {\n\tif vr, ok := d.DiffDriver.(interface {\n\t\tViewDefChanged(v1, v2 *schema.View) bool\n\t}); ok {\n\t\treturn vr.ViewDefChanged(v1, v2)\n\t}\n\treturn BodyDefChanged(v1.Def, v2.Def)\n}\n\n// columnDiffV returns the schema changes (if any) for migrating view columns.\n// Currently, only comment changes are supported.\nfunc (d *Diff) columnDiffV(from, to *schema.View, opts *schema.DiffOptions) ([]schema.Change, error) {\n\tvar changes []schema.Change\n\tfor _, c1 := range from.Columns {\n\t\tc2, ok := to.Column(c1.Name)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif change := CommentChange(c1.Attrs, c2.Attrs); change != schema.NoChange {\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.ModifyColumn{\n\t\t\t\tFrom:   c1,\n\t\t\t\tTo:     c2,\n\t\t\t\tChange: change,\n\t\t\t})\n\t\t}\n\t}\n\treturn changes, nil\n}\n\n// indexDiffV returns the schema changes (if any) for migrating view\n// indexes from current state to the desired state.\nfunc (d *Diff) indexDiffV(from, to *schema.View, opts *schema.DiffOptions) ([]schema.Change, error) {\n\tvar (\n\t\tchanges []schema.Change\n\t\texists  = make(map[*schema.Index]bool)\n\t)\n\t// Drop or modify indexes.\n\tfor _, idx1 := range from.Indexes {\n\t\tidx2, ok := to.Index(idx1.Name)\n\t\tif ok {\n\t\t\tif change := d.indexChange(idx1, idx2); change != schema.NoChange {\n\t\t\t\tchanges = opts.AddOrSkip(changes, &schema.ModifyIndex{\n\t\t\t\t\tFrom:   idx1,\n\t\t\t\t\tTo:     idx2,\n\t\t\t\t\tChange: change,\n\t\t\t\t})\n\t\t\t}\n\t\t\texists[idx2] = true\n\t\t\tcontinue\n\t\t}\n\t\t// Not found.\n\t\tchanges = opts.AddOrSkip(changes, &schema.DropIndex{I: idx1})\n\t}\n\t// Add indexes.\n\tfor _, idx := range to.Indexes {\n\t\tif exists[idx] {\n\t\t\tcontinue\n\t\t}\n\t\tif _, ok := from.Index(idx.Name); !ok {\n\t\t\tchanges = opts.AddOrSkip(changes, &schema.AddIndex{I: idx})\n\t\t}\n\t}\n\treturn d.askForIndexes(from.Name, changes, opts)\n}\n\n// indexChange returns the schema changes (if any) for migrating one index to the other.\nfunc (d *Diff) indexChange(from, to *schema.Index) schema.ChangeKind {\n\tvar change schema.ChangeKind\n\tif from.Unique != to.Unique {\n\t\tchange |= schema.ChangeUnique\n\t}\n\tif d.IndexAttrChanged(from.Attrs, to.Attrs) {\n\t\tchange |= schema.ChangeAttr\n\t}\n\tchange |= d.partsChange(from, to, nil)\n\tchange |= CommentChange(from.Attrs, to.Attrs)\n\treturn change\n}\n\nfunc (d *Diff) partsChange(fromI, toI *schema.Index, renames map[string]string) schema.ChangeKind {\n\tfrom, to := fromI.Parts, toI.Parts\n\tif len(from) != len(to) {\n\t\treturn schema.ChangeParts\n\t}\n\tsort.Slice(to, func(i, j int) bool { return to[i].SeqNo < to[j].SeqNo })\n\tsort.Slice(from, func(i, j int) bool { return from[i].SeqNo < from[j].SeqNo })\n\tfor i := range from {\n\t\tswitch {\n\t\tcase from[i].Desc != to[i].Desc || d.IndexPartAttrChanged(fromI, toI, i):\n\t\t\treturn schema.ChangeParts\n\t\tcase from[i].C != nil && to[i].C != nil:\n\t\t\tif from[i].C.Name != to[i].C.Name && renames[from[i].C.Name] != to[i].C.Name {\n\t\t\t\treturn schema.ChangeParts\n\t\t\t}\n\t\tcase from[i].X != nil && to[i].X != nil:\n\t\t\tx1, x2 := from[i].X.(*schema.RawExpr).X, to[i].X.(*schema.RawExpr).X\n\t\t\tif x1 != x2 && x1 != MayWrap(x2) {\n\t\t\t\treturn schema.ChangeParts\n\t\t\t}\n\t\tdefault: // (C1 != nil) != (C2 != nil) || (X1 != nil) != (X2 != nil).\n\t\t\treturn schema.ChangeParts\n\t\t}\n\t}\n\treturn schema.NoChange\n}\n\n// fkChange returns the schema changes (if any) for migrating one index to the other.\nfunc (d *Diff) fkChange(from, to *schema.ForeignKey) schema.ChangeKind {\n\tvar change schema.ChangeKind\n\tswitch {\n\tcase from.RefTable.Name != to.RefTable.Name:\n\t\tchange |= schema.ChangeRefTable | schema.ChangeRefColumn\n\tcase len(from.RefColumns) != len(to.RefColumns):\n\t\tchange |= schema.ChangeRefColumn\n\tdefault:\n\t\tfor i := range from.RefColumns {\n\t\t\tif from.RefColumns[i].Name != to.RefColumns[i].Name {\n\t\t\t\tchange |= schema.ChangeRefColumn\n\t\t\t}\n\t\t}\n\t}\n\tswitch {\n\tcase len(from.Columns) != len(to.Columns):\n\t\tchange |= schema.ChangeColumn\n\tdefault:\n\t\tfor i := range from.Columns {\n\t\t\tif from.Columns[i].Name != to.Columns[i].Name {\n\t\t\t\tchange |= schema.ChangeColumn\n\t\t\t}\n\t\t}\n\t}\n\tif d.ReferenceChanged(from.OnUpdate, to.OnUpdate) {\n\t\tchange |= schema.ChangeUpdateAction\n\t}\n\tif d.ReferenceChanged(from.OnDelete, to.OnDelete) {\n\t\tchange |= schema.ChangeDeleteAction\n\t}\n\tif d.ForeignKeyAttrChanged(from.Attrs, to.Attrs) {\n\t\tchange |= schema.ChangeAttr\n\t}\n\treturn change\n}\n\n// similarUnnamedIndex searches for an unnamed index with the same index-parts in the table.\nfunc (d *Diff) similarUnnamedIndex(t *schema.Table, idx1 *schema.Index) (*schema.Index, bool) {\n\tmatch := func(idx1, idx2 *schema.Index) bool {\n\t\treturn idx1.Unique == idx2.Unique && d.partsChange(idx1, idx2, nil) == schema.NoChange\n\t}\n\tif f, ok := d.DiffDriver.(interface {\n\t\tFindGeneratedIndex(*schema.Table, *schema.Index) (*schema.Index, bool)\n\t}); ok {\n\t\tif idx2, ok := f.FindGeneratedIndex(t, idx1); ok && match(idx1, idx2) {\n\t\t\treturn idx2, true\n\t\t}\n\t}\n\tfor _, idx2 := range t.Indexes {\n\t\tif idx2.Name == \"\" && match(idx1, idx2) {\n\t\t\treturn idx2, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\nfunc (d *Diff) findTable(s *schema.Schema, t1 *schema.Table) (*schema.Table, error) {\n\tif f, ok := d.DiffDriver.(TableFinder); ok {\n\t\treturn f.FindTable(s, t1)\n\t}\n\tt2, ok := s.Table(t1.Name)\n\tif !ok {\n\t\treturn nil, &schema.NotExistError{Err: fmt.Errorf(\"table %q was not found\", t1.Name)}\n\t}\n\treturn t2, nil\n}\n\n// CommentChange reports if the element comment was changed.\nfunc CommentChange(from, to []schema.Attr) schema.ChangeKind {\n\tvar c1, c2 schema.Comment\n\tif Has(from, &c1) != Has(to, &c2) || c1.Text != c2.Text {\n\t\treturn schema.ChangeComment\n\t}\n\treturn schema.NoChange\n}\n\n// Charset reports if the attribute contains the \"charset\" attribute,\n// and it needs to be defined explicitly on the schema. This is true, in\n// case the element charset is different from its parent charset.\nfunc Charset(attr, parent []schema.Attr) (string, bool) {\n\tvar c, p schema.Charset\n\tif Has(attr, &c) && (parent == nil || Has(parent, &p) && c.V != p.V) {\n\t\treturn c.V, true\n\t}\n\treturn \"\", false\n}\n\n// Collate reports if the attribute contains the \"collation\"/\"collate\" attribute,\n// and it needs to be defined explicitly on the schema. This is true, in\n// case the element collation is different from its parent collation.\nfunc Collate(attr, parent []schema.Attr) (string, bool) {\n\tvar c, p schema.Collation\n\tif Has(attr, &c) && (parent == nil || Has(parent, &p) && c.V != p.V) {\n\t\treturn c.V, true\n\t}\n\treturn \"\", false\n}\n\nvar (\n\tattrsType   = reflect.TypeOf(([]schema.Attr)(nil))\n\tclausesType = reflect.TypeOf(([]schema.Clause)(nil))\n\texprsType   = reflect.TypeOf(([]schema.Expr)(nil))\n)\n\n// AttrOr returns the first attribute of the given type,\n// or the given default value.\nfunc AttrOr[T schema.Attr](attrs []schema.Attr, t T) T {\n\tfor _, attr := range attrs {\n\t\tif a, ok := attr.(T); ok {\n\t\t\treturn a\n\t\t}\n\t}\n\treturn t\n}\n\n// Has finds the first element in the elements list that\n// matches target, and if so, sets target to that attribute\n// value and returns true.\nfunc Has(elements, target any) bool {\n\tev := reflect.ValueOf(elements)\n\tif t := ev.Type(); t != attrsType && t != clausesType && t != exprsType {\n\t\tpanic(fmt.Sprintf(\"unexpected elements type: %T\", elements))\n\t}\n\ttv := reflect.ValueOf(target)\n\tif tv.Kind() != reflect.Ptr || tv.IsNil() {\n\t\tpanic(\"target must be a non-nil pointer\")\n\t}\n\tfor i := 0; i < ev.Len(); i++ {\n\t\tidx := ev.Index(i)\n\t\tif idx.IsNil() {\n\t\t\tcontinue\n\t\t}\n\t\tif e := idx.Elem(); e.Type().AssignableTo(tv.Type()) {\n\t\t\ttv.Elem().Set(e.Elem())\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// UnsupportedTypeError describes an unsupported type error.\ntype UnsupportedTypeError struct {\n\tschema.Type\n}\n\nfunc (e UnsupportedTypeError) Error() string {\n\treturn fmt.Sprintf(\"unsupported type %T\", e.Type)\n}\n\n// CommentDiff computes the comment diff between the 2 attribute list.\n// Note that, the implementation relies on the fact that both PostgreSQL\n// and MySQL treat empty comment as \"no comment\" and a way to clear comments.\nfunc CommentDiff(from, to []schema.Attr) schema.Change {\n\tvar fromC, toC schema.Comment\n\tswitch fromHas, toHas := Has(from, &fromC), Has(to, &toC); {\n\tcase !fromHas && !toHas:\n\tcase !fromHas && toC.Text != \"\":\n\t\treturn &schema.AddAttr{\n\t\t\tA: &toC,\n\t\t}\n\tcase !toHas:\n\t\t// In MySQL, there is no way to DROP a comment. Instead, setting it to empty ('')\n\t\t// will remove it from INFORMATION_SCHEMA. We use the same approach in PostgreSQL,\n\t\t// because comments can be dropped either by setting them to NULL or empty string.\n\t\t// See: postgres/backend/commands/comment.c#CreateComments.\n\t\treturn &schema.ModifyAttr{\n\t\t\tFrom: &fromC,\n\t\t\tTo:   &toC,\n\t\t}\n\tdefault:\n\t\tv1, err1 := Unquote(fromC.Text)\n\t\tv2, err2 := Unquote(toC.Text)\n\t\tif err1 == nil && err2 == nil && v1 != v2 {\n\t\t\treturn &schema.ModifyAttr{\n\t\t\t\tFrom: &fromC,\n\t\t\t\tTo:   &toC,\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// CheckDiffMode is like CheckDiff, but compares also expressions\n// if the schema.DiffMode is equal to schema.DiffModeNormalized.\nfunc CheckDiffMode(from, to *schema.Table, mode schema.DiffMode, compare ...func(c1, c2 *schema.Check) bool) []schema.Change {\n\tif !mode.Is(schema.DiffModeNormalized) {\n\t\treturn checksSimilarDiff(from, to, compare...)\n\t}\n\treturn ChecksDiff(from, to, func(c1, c2 *schema.Check) bool {\n\t\tif len(compare) == 1 && !compare[0](c1, c2) {\n\t\t\treturn false\n\t\t}\n\t\treturn c1.Expr == c2.Expr || MayWrap(c1.Expr) == MayWrap(c2.Expr)\n\t})\n}\n\n// ChecksDiff computes the change diff between the 2 tables.\nfunc ChecksDiff(from, to *schema.Table, compare func(c1, c2 *schema.Check) bool) []schema.Change {\n\tvar (\n\t\tchanges    []schema.Change\n\t\tfromC, toC = checks(from.Attrs), checks(to.Attrs)\n\t\tcompareTo  = func(c1 *schema.Check) func(c2 *schema.Check) bool {\n\t\t\treturn func(c2 *schema.Check) bool {\n\t\t\t\tif c1.Name != \"\" && c2.Name != \"\" {\n\t\t\t\t\t// Only compare by name if both have a name.\n\t\t\t\t\treturn c1.Name == c2.Name\n\t\t\t\t}\n\t\t\t\treturn compare(c1, c2)\n\t\t\t}\n\t\t}\n\t)\n\tfor _, c1 := range fromC {\n\t\tswitch idx := slices.IndexFunc(toC, compareTo(c1)); {\n\t\tcase idx == -1:\n\t\t\tchanges = append(changes, &schema.DropCheck{\n\t\t\t\tC: c1,\n\t\t\t})\n\t\tcase !compare(c1, toC[idx]):\n\t\t\tchanges = append(changes, &schema.ModifyCheck{\n\t\t\t\tFrom: c1,\n\t\t\t\tTo:   toC[idx],\n\t\t\t})\n\t\t}\n\t}\n\tfor _, c1 := range toC {\n\t\tif !slices.ContainsFunc(fromC, compareTo(c1)) {\n\t\t\tchanges = append(changes, &schema.AddCheck{\n\t\t\t\tC: c1,\n\t\t\t})\n\t\t}\n\t}\n\treturn changes\n}\n\n// checksSimilarDiff computes the change diff between the 2 tables.\n// Unlike ChecksDiff, it does not compare the constraint name, but\n// determines if there is any similar constraint by its expression.\n// This is an old implementation that is not used anymore by the CLI.\nfunc checksSimilarDiff(from, to *schema.Table, compare ...func(c1, c2 *schema.Check) bool) []schema.Change {\n\tvar changes []schema.Change\n\t// Drop or modify checks.\n\tfor _, c1 := range checks(from.Attrs) {\n\t\tswitch c2, ok := similarCheck(to.Attrs, c1); {\n\t\tcase !ok:\n\t\t\tchanges = append(changes, &schema.DropCheck{\n\t\t\t\tC: c1,\n\t\t\t})\n\t\tcase len(compare) == 1 && !compare[0](c1, c2):\n\t\t\tchanges = append(changes, &schema.ModifyCheck{\n\t\t\t\tFrom: c1,\n\t\t\t\tTo:   c2,\n\t\t\t})\n\t\t}\n\t}\n\t// Add checks.\n\tfor _, c1 := range checks(to.Attrs) {\n\t\tif _, ok := similarCheck(from.Attrs, c1); !ok {\n\t\t\tchanges = append(changes, &schema.AddCheck{\n\t\t\t\tC: c1,\n\t\t\t})\n\t\t}\n\t}\n\treturn changes\n}\n\n// checks extracts all constraints from table attributes.\nfunc checks(attr []schema.Attr) (checks []*schema.Check) {\n\tfor i := range attr {\n\t\tif c, ok := attr[i].(*schema.Check); ok {\n\t\t\tchecks = append(checks, c)\n\t\t}\n\t}\n\treturn checks\n}\n\n// similarCheck returns a CHECK by its constraints name or expression.\nfunc similarCheck(attrs []schema.Attr, c *schema.Check) (*schema.Check, bool) {\n\tvar byName, byExpr *schema.Check\n\tfor i := 0; i < len(attrs) && (byName == nil || byExpr == nil); i++ {\n\t\tcheck, ok := attrs[i].(*schema.Check)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif check.Name != \"\" && check.Name == c.Name {\n\t\t\tbyName = check\n\t\t}\n\t\tif check.Expr == c.Expr || MayWrap(check.Expr) == MayWrap(c.Expr) {\n\t\t\tbyExpr = check\n\t\t}\n\t}\n\t// Give precedence to constraint name.\n\tif byName != nil {\n\t\treturn byName, true\n\t}\n\tif byExpr != nil {\n\t\treturn byExpr, true\n\t}\n\treturn nil, false\n}\n\n// Unquote single or double quotes.\nfunc Unquote(s string) (string, error) {\n\tswitch {\n\tcase IsQuoted(s, '\"'):\n\t\treturn strconv.Unquote(s)\n\tcase IsQuoted(s, '\\''):\n\t\treturn strings.ReplaceAll(s[1:len(s)-1], \"''\", \"'\"), nil\n\tdefault:\n\t\treturn s, nil\n\t}\n}\n\n// SingleQuote quotes the given string with single quote.\nfunc SingleQuote(s string) (string, error) {\n\tswitch {\n\tcase IsQuoted(s, '\\''):\n\t\treturn s, nil\n\tcase IsQuoted(s, '\"'):\n\t\tv, err := strconv.Unquote(s)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\ts = v\n\t\tfallthrough\n\tdefault:\n\t\treturn \"'\" + strings.ReplaceAll(s, \"'\", \"''\") + \"'\", nil\n\t}\n}\n\n// TrimViewExtra trims the extra unnecessary\n// characters from the view definition.\nfunc TrimViewExtra(s string) string {\n\treturn strings.Trim(s, \" \\r\\n\\t;\")\n}\n\n// BodyDefChanged reports if the body definition of a function, procedure, view, or\n// trigger has changed. There is a small task here that normalizes the indentation,\n// which might be added during inspection or by the user.\nfunc BodyDefChanged(from, to string) bool {\n\tif from == to {\n\t\treturn false // Exact match.\n\t}\n\tif from, to = TrimViewExtra(from), TrimViewExtra(to); from == to {\n\t\treturn false // Match after trimming.\n\t}\n\tnoident := func(v string) string {\n\t\tvar b strings.Builder\n\t\tfor i, s := range strings.Split(v, \"\\n\") {\n\t\t\tif s = TrimViewExtra(s); s != \"\" && i > 0 {\n\t\t\t\tb.WriteByte(' ')\n\t\t\t}\n\t\t\tb.WriteString(s)\n\t\t}\n\t\treturn b.String()\n\t}\n\treturn noident(from) != noident(to)\n}\n\n// findView finds the view by its name and its type.\nfunc findView(s *schema.Schema, v1 *schema.View) (*schema.View, bool) {\n\tif v1.Materialized() {\n\t\treturn s.Materialized(v1.Name)\n\t}\n\treturn s.View(v1.Name)\n}\n"
  },
  {
    "path": "sql/internal/sqlx/plan.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlx\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"sort\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\ntype (\n\texecPlanner interface {\n\t\tExecContext(context.Context, string, ...any) (sql.Result, error)\n\t\tPlanChanges(context.Context, string, []schema.Change, ...migrate.PlanOption) (*migrate.Plan, error)\n\t}\n\t// ApplyError is an error that exposes an information for getting\n\t// how any changes were applied before encountering the failure.\n\tApplyError struct {\n\t\terr     string\n\t\tapplied int\n\t}\n)\n\n// Applied reports how many changes were applied before getting an error.\n// In case the first change was failed, Applied() returns 0.\nfunc (e *ApplyError) Applied() int {\n\treturn e.applied\n}\n\n// Error implements the error interface.\nfunc (e *ApplyError) Error() string {\n\treturn e.err\n}\n\n// ApplyChanges is a helper used by the different drivers to apply changes.\nfunc ApplyChanges(ctx context.Context, changes []schema.Change, p execPlanner, opts ...migrate.PlanOption) error {\n\tplan, err := p.PlanChanges(ctx, \"apply\", changes, opts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor i, c := range plan.Changes {\n\t\tif _, err := p.ExecContext(ctx, c.Cmd, c.Args...); err != nil {\n\t\t\tif c.Comment != \"\" {\n\t\t\t\terr = fmt.Errorf(\"%s: %w\", c.Comment, err)\n\t\t\t}\n\t\t\treturn &ApplyError{err: err.Error(), applied: i}\n\t\t}\n\t}\n\treturn nil\n}\n\n// noRows implements the schema.ExecQuerier for migrate.Driver's without connections.\n// This can be useful to always return no rows for queries, and block any execution.\ntype noRows struct{}\n\n// QueryContext implements the sqlx.ExecQuerier interface.\nfunc (*noRows) QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) {\n\treturn nil, sql.ErrNoRows\n}\n\n// ExecContext implements the sqlx.ExecQuerier interface.\nfunc (*noRows) ExecContext(context.Context, string, ...interface{}) (sql.Result, error) {\n\treturn nil, errors.New(\"cannot execute statements without a database connection. use Open to create a new Driver\")\n}\n\n// NoRows to be used by differs and planners without a connection.\nvar NoRows schema.ExecQuerier = (*noRows)(nil)\n\n// SetReversible sets the Reversible field to\n// true if all planned changes are reversible.\nfunc SetReversible(p *migrate.Plan) error {\n\treversible := true\n\tfor _, c := range p.Changes {\n\t\tstmts, err := c.ReverseStmts()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(stmts) == 0 {\n\t\t\treversible = false\n\t\t}\n\t}\n\tp.Reversible = reversible\n\treturn nil\n}\n\n// DetachCycles takes a list of schema changes, and detaches\n// references between changes if there is at least one circular\n// reference in the changeset. More explicitly, it postpones fks\n// creation, or deletes fks before deletes their tables.\nfunc DetachCycles(changes []schema.Change) ([]schema.Change, error) {\n\tsorted, err := sortMap(changes)\n\tif errors.Is(err, errCycle) {\n\t\treturn detachReferences(changes), nil\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tplanned := make([]schema.Change, len(changes))\n\tcopy(planned, changes)\n\tsort.Slice(planned, func(i, j int) bool {\n\t\treturn sorted[table(planned[i])] < sorted[table(planned[j])]\n\t})\n\treturn planned, nil\n}\n\n// detachReferences detaches all table references.\nfunc detachReferences(changes []schema.Change) []schema.Change {\n\tvar planned, deferred []schema.Change\n\tfor _, change := range changes {\n\t\tswitch change := change.(type) {\n\t\tcase *schema.AddTable:\n\t\t\tvar (\n\t\t\t\text  []schema.Change\n\t\t\t\tself []*schema.ForeignKey\n\t\t\t)\n\t\t\tfor _, fk := range change.T.ForeignKeys {\n\t\t\t\tif fk.RefTable == change.T {\n\t\t\t\t\tself = append(self, fk)\n\t\t\t\t} else {\n\t\t\t\t\text = append(ext, &schema.AddForeignKey{F: fk})\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(ext) > 0 {\n\t\t\t\tdeferred = append(deferred, &schema.ModifyTable{T: change.T, Changes: ext})\n\t\t\t\tt := *change.T\n\t\t\t\tt.ForeignKeys = self\n\t\t\t\tchange = &schema.AddTable{T: &t, Extra: change.Extra}\n\t\t\t}\n\t\t\tplanned = append(planned, change)\n\t\tcase *schema.DropTable:\n\t\t\tvar fks []schema.Change\n\t\t\tfor _, fk := range change.T.ForeignKeys {\n\t\t\t\tif fk.RefTable != change.T {\n\t\t\t\t\tfks = append(fks, &schema.DropForeignKey{F: fk})\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(fks) > 0 {\n\t\t\t\tplanned = append(planned, &schema.ModifyTable{T: change.T, Changes: fks})\n\t\t\t\tt := *change.T\n\t\t\t\tt.ForeignKeys = nil\n\t\t\t\tchange = &schema.DropTable{T: &t, Extra: change.Extra}\n\t\t\t}\n\t\t\tdeferred = append(deferred, change)\n\t\tcase *schema.ModifyTable:\n\t\t\tvar fks, rest []schema.Change\n\t\t\tfor _, c := range change.Changes {\n\t\t\t\tswitch c := c.(type) {\n\t\t\t\tcase *schema.AddForeignKey:\n\t\t\t\t\tfks = append(fks, c)\n\t\t\t\tdefault:\n\t\t\t\t\trest = append(rest, c)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(fks) > 0 {\n\t\t\t\tdeferred = append(deferred, &schema.ModifyTable{T: change.T, Changes: fks})\n\t\t\t}\n\t\t\tif len(rest) > 0 {\n\t\t\t\tplanned = append(planned, &schema.ModifyTable{T: change.T, Changes: rest})\n\t\t\t}\n\t\tdefault:\n\t\t\tplanned = append(planned, change)\n\t\t}\n\t}\n\treturn append(planned, deferred...)\n}\n\n// errCycle is an internal error to indicate a case of a cycle.\nvar errCycle = errors.New(\"cycle detected\")\n\n// sortMap returns an index-map indicates the position of table in a topological\n// sort in reversed order based on its references, and a boolean indicate if there\n// is a non-self loop.\nfunc sortMap(changes []schema.Change) (map[string]int, error) {\n\tvar (\n\t\tvisit     func(string) bool\n\t\tsorted    = make(map[string]int)\n\t\tprogress  = make(map[string]bool)\n\t\tdeps, err = dependencies(changes)\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvisit = func(name string) bool {\n\t\tif _, done := sorted[name]; done {\n\t\t\treturn false\n\t\t}\n\t\tif progress[name] {\n\t\t\treturn true\n\t\t}\n\t\tprogress[name] = true\n\t\tfor _, ref := range deps[name] {\n\t\t\tif visit(ref.Name) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\tdelete(progress, name)\n\t\tsorted[name] = len(sorted)\n\t\treturn false\n\t}\n\tfor _, node := range byKeys(deps) {\n\t\tif visit(node.K) {\n\t\t\treturn nil, errCycle\n\t\t}\n\t}\n\treturn sorted, nil\n}\n\n// dependencies returned an adjacency list of all tables and the tables they depend on.\nfunc dependencies(changes []schema.Change) (map[string][]*schema.Table, error) {\n\tdeps := make(map[string][]*schema.Table)\n\tfor _, change := range changes {\n\t\tswitch change := change.(type) {\n\t\tcase *schema.AddTable:\n\t\t\tfor _, fk := range change.T.ForeignKeys {\n\t\t\t\tif err := checkFK(fk); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif fk.RefTable != change.T {\n\t\t\t\t\tdeps[change.T.Name] = append(deps[change.T.Name], fk.RefTable)\n\t\t\t\t}\n\t\t\t}\n\t\tcase *schema.DropTable:\n\t\t\tfor _, fk := range change.T.ForeignKeys {\n\t\t\t\tif err := checkFK(fk); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif isDropped(changes, fk.RefTable) {\n\t\t\t\t\tdeps[fk.RefTable.Name] = append(deps[fk.RefTable.Name], fk.Table)\n\t\t\t\t}\n\t\t\t}\n\t\tcase *schema.ModifyTable:\n\t\t\tfor _, c := range change.Changes {\n\t\t\t\tswitch c := c.(type) {\n\t\t\t\tcase *schema.AddForeignKey:\n\t\t\t\t\tif err := checkFK(c.F); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tif c.F.RefTable != change.T {\n\t\t\t\t\t\tdeps[change.T.Name] = append(deps[change.T.Name], c.F.RefTable)\n\t\t\t\t\t}\n\t\t\t\tcase *schema.ModifyForeignKey:\n\t\t\t\t\tif err := checkFK(c.To); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tif c.To.RefTable != change.T {\n\t\t\t\t\t\tdeps[change.T.Name] = append(deps[change.T.Name], c.To.RefTable)\n\t\t\t\t\t}\n\t\t\t\tcase *schema.DropForeignKey:\n\t\t\t\t\tif err := checkFK(c.F); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tif isDropped(changes, c.F.RefTable) {\n\t\t\t\t\t\tdeps[c.F.RefTable.Name] = append(deps[c.F.RefTable.Name], c.F.Table)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn deps, nil\n}\n\nfunc checkFK(fk *schema.ForeignKey) error {\n\tvar cause []string\n\tif fk.Table == nil {\n\t\tcause = append(cause, \"child table\")\n\t}\n\tif len(fk.Columns) == 0 {\n\t\tcause = append(cause, \"child columns\")\n\t}\n\tif fk.RefTable == nil {\n\t\tcause = append(cause, \"parent table\")\n\t}\n\tif len(fk.RefColumns) == 0 {\n\t\tcause = append(cause, \"parent columns\")\n\t}\n\tif len(cause) != 0 {\n\t\treturn fmt.Errorf(\"missing %q for foreign key: %q\", cause, fk.Symbol)\n\t}\n\treturn nil\n}\n\n// table extracts a table from the given change.\nfunc table(change schema.Change) (t string) {\n\tswitch change := change.(type) {\n\tcase *schema.AddTable:\n\t\tt = change.T.Name\n\tcase *schema.DropTable:\n\t\tt = change.T.Name\n\tcase *schema.ModifyTable:\n\t\tt = change.T.Name\n\t}\n\treturn\n}\n\n// isDropped checks if the given table is marked as a deleted in the changeset.\nfunc isDropped(changes []schema.Change, t *schema.Table) bool {\n\tfor _, c := range changes {\n\t\tif c, ok := c.(*schema.DropTable); ok && c.T.Name == t.Name {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// CheckChangesScope checks that changes can be applied\n// on a schema scope (connection).\nfunc CheckChangesScope(opts migrate.PlanOptions, changes []schema.Change) error {\n\tnames := make(map[string]struct{})\n\tfor _, c := range changes {\n\t\tvar t *schema.Table\n\t\tswitch c := c.(type) {\n\t\tcase *schema.ModifySchema:\n\t\t\tswitch scope := V(opts.SchemaQualifier); {\n\t\t\tcase !opts.Mode.Is(migrate.PlanModeInPlace):\n\t\t\t\t// The migration plan is generated for deferred execution.\n\t\t\t\treturn fmt.Errorf(\"%T is not allowed when migration plan is scoped to one schema\", c)\n\t\t\tcase scope != \"\" && scope != c.S.Name:\n\t\t\t\t// Other schemas can not be modified when the migration plan is scoped to one schema.\n\t\t\t\treturn fmt.Errorf(\"modify schema %s is not allowed when migration plan is scoped to schema %s\", c.S.Name, scope)\n\t\t\tdefault:\n\t\t\t\tnames[c.S.Name] = struct{}{}\n\t\t\t\tcontinue\n\t\t\t}\n\t\tcase *schema.AddSchema, *schema.DropSchema:\n\t\t\treturn fmt.Errorf(\"%T is not allowed when migration plan is scoped to one schema\", c)\n\t\tcase *schema.AddTable:\n\t\t\tt = c.T\n\t\tcase *schema.ModifyTable:\n\t\t\tt = c.T\n\t\tcase *schema.DropTable:\n\t\t\tt = c.T\n\t\tdefault:\n\t\t\tcontinue\n\t\t}\n\t\tif t.Schema != nil && t.Schema.Name != \"\" {\n\t\t\tnames[t.Schema.Name] = struct{}{}\n\t\t}\n\t\tfor _, c := range t.Columns {\n\t\t\te, ok := c.Type.Type.(*schema.EnumType)\n\t\t\tif ok && e.Schema != nil && e.Schema.Name != \"\" {\n\t\t\t\tnames[t.Schema.Name] = struct{}{}\n\t\t\t}\n\t\t}\n\t}\n\tif len(names) > 1 {\n\t\tks := make([]string, 0, len(names))\n\t\tfor k := range names {\n\t\t\tks = append(ks, k)\n\t\t}\n\t\tsort.Strings(ks)\n\t\treturn fmt.Errorf(\"found %d schemas when migration plan is scoped to one: %q\", len(names), ks)\n\t}\n\treturn nil\n}\n\n// byKeys sorts a map by keys.\nfunc byKeys[T any](m map[string]T) []struct {\n\tK string\n\tV T\n} {\n\tvs := make([]struct {\n\t\tK string\n\t\tV T\n\t}, 0, len(m))\n\tfor k, v := range m {\n\t\tvs = append(vs, struct {\n\t\t\tK string\n\t\t\tV T\n\t\t}{k, v})\n\t}\n\tsort.Slice(vs, func(i, j int) bool {\n\t\treturn vs[i].K < vs[j].K\n\t})\n\treturn vs\n}\n\n// SortOptions allows drivers to customize the behavior of the SortChanges function.\ntype SortOptions struct {\n\t// FuncDepT reports if a function depends on the given table.\n\tFuncDepT func(*schema.Func, *schema.Table) bool\n\t// FuncDepV reports if a function depends on the given view.\n\tFuncDepV func(*schema.Func, *schema.View) bool\n\t// FuncDepO reports if a function depends on the given object.\n\tFuncDepO func(*schema.Func, schema.Object) bool\n\t// ProcDepT reports if a procedure depends on the given table.\n\tProcDepT func(*schema.Proc, *schema.Table) bool\n\t// ProcDepO reports if a procedure depends on the given object.\n\tProcDepO func(*schema.Proc, schema.Object) bool\n\t// ViewDepT reports if a view depends on the given table.\n\tViewDepT func(*schema.View, *schema.Table) bool\n\t// CompareFuncArgs set to true to compare function arguments.\n\tCompareFuncArgs bool\n\t// DefaultSchema defines the default schema (also known as \"search_path\") that\n\t// is used by the database to search for objects if no qualifier is provided.\n\tDefaultSchema string\n}\n\n// SortChanges is a helper function to sort to level changes based on their priority.\nfunc SortChanges(changes []schema.Change, opts *SortOptions) []schema.Change {\n\tvar views, drop, other []schema.Change\n\tfor _, c := range changes {\n\t\tswitch c.(type) {\n\t\tcase *schema.AddView, *schema.DropView, *schema.ModifyView:\n\t\t\tviews = append(views, c)\n\t\tcase *schema.DropSchema, *schema.DropTable, *schema.DropFunc, *schema.DropProc, *schema.DropObject:\n\t\t\tdrop = append(drop, c)\n\t\tdefault:\n\t\t\tother = append(other, c)\n\t\t}\n\t}\n\tif planned, err := sortViewChanges(views); err == nil { // no cycles.\n\t\tviews = planned\n\t}\n\t// To keep backwards compatibility with previous sorting and also in case we miss any dependency between changes\n\t// (see, dependsOn function) we push views and drop changes to the end, unless there is a dependency requirement.\n\tchanges = append(other, append(views, drop...)...)\n\tvar (\n\t\thasE  = make(map[struct{ e1, e2 schema.Change }]bool)\n\t\tedges = make(map[schema.Change][]schema.Change)\n\t)\n\tfor _, c1 := range changes {\n\t\tfor _, c2 := range changes {\n\t\t\t// Skip checking dependencies between the same change. Also, if the inverse\n\t\t\t// dependency is already added, skip it, as circular dependencies are not expected.\n\t\t\tif c1 != c2 && !hasE[struct{ e1, e2 schema.Change }{c2, c1}] && dependsOn(c1, c2, V(opts)) {\n\t\t\t\tedges[c1] = append(edges[c1], c2)\n\t\t\t\thasE[struct{ e1, e2 schema.Change }{c1, c2}] = true\n\t\t\t}\n\t\t}\n\t}\n\tvar (\n\t\tadd     func(schema.Change)\n\t\tadded   = make(map[schema.Change]bool)\n\t\tplanned = make([]schema.Change, 0, len(changes))\n\t)\n\tadd = func(c schema.Change) {\n\t\tif added[c] {\n\t\t\treturn\n\t\t}\n\t\tadded[c] = true\n\t\tfor _, d := range edges[c] {\n\t\t\tif !added[d] {\n\t\t\t\tadd(d)\n\t\t\t}\n\t\t}\n\t\tplanned = append(planned, c)\n\t}\n\tfor _, c := range changes {\n\t\tif !added[c] {\n\t\t\tadd(c)\n\t\t}\n\t}\n\treturn planned\n}\n\ntype (\n\t// Depender can be implemented by an object to determine if a change to it\n\t// depends on other change, or if other change depends on it. For example:\n\t// A table creation depends on type creation, and a type deletion depends on\n\t// table deletion.\n\tDepender interface {\n\t\tDependsOn(change, other schema.Change) bool\n\t\tDependencyOf(change, other schema.Change) bool\n\t}\n\t// RowTyper can be implemented by a type to determine if its source\n\t// is a regular table (e.g., row types).\n\tRowTyper interface {\n\t\tRowTypeT() *schema.Table\n\t\tRowTypeV() *schema.View\n\t}\n)\n\n// dependOnOf checks if the given change depends on the other change or\n// vice versa based on their underlying object implementation.\nfunc dependOnOf(change, other schema.Change) bool {\n\tswitch change := change.(type) {\n\tcase *schema.AddObject:\n\t\tif d, ok := change.O.(Depender); ok && d.DependsOn(change, other) {\n\t\t\treturn true\n\t\t}\n\tcase *schema.ModifyObject:\n\t\tif d, ok := change.To.(Depender); ok && d.DependsOn(change, other) {\n\t\t\treturn true\n\t\t}\n\tcase *schema.DropObject:\n\t\tif d, ok := change.O.(Depender); ok && d.DependsOn(change, other) {\n\t\t\treturn true\n\t\t}\n\t}\n\tswitch other := other.(type) {\n\tcase *schema.AddObject:\n\t\tif d, ok := other.O.(Depender); ok && d.DependencyOf(other, change) {\n\t\t\treturn true\n\t\t}\n\tcase *schema.ModifyObject:\n\t\tif d, ok := other.To.(Depender); ok && d.DependencyOf(other, change) {\n\t\t\treturn true\n\t\t}\n\tcase *schema.DropObject:\n\t\tif d, ok := other.O.(Depender); ok && d.DependencyOf(other, change) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// depOfDrops checks if the given object is a dependency of the given change.\nfunc depOfDrop(o schema.Object, c schema.Change) bool {\n\tvar deps []schema.Object\n\tswitch c := c.(type) {\n\tcase *schema.DropTable:\n\t\tdeps = c.T.Deps\n\t\tfor _, t := range c.T.Triggers {\n\t\t\tfor _, d := range t.Deps {\n\t\t\t\t// If the trigger depends on the table that has FK to its parent,\n\t\t\t\t// this dependency should be ignored as the FK need be dropped first.\n\t\t\t\tif t, ok := d.(*schema.Table); !ok || !refTo(t.ForeignKeys, c.T) {\n\t\t\t\t\tdeps = append(deps, d)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\tcase *schema.DropView:\n\t\tdeps = c.V.Deps\n\t\tfor _, t := range c.V.Triggers {\n\t\t\tdeps = append(deps, t.Deps...)\n\t\t}\n\tcase *schema.DropFunc:\n\t\tdeps = c.F.Deps\n\tcase *schema.DropProc:\n\t\tdeps = c.P.Deps\n\tcase *schema.DropTrigger:\n\t\tdeps = c.T.Deps\n\t}\n\treturn slices.Contains(deps, o)\n}\n\n// depOfAdd checks if the given change is a creation of a resource exists in the given list.\nfunc depOfAdd(refs []schema.Object, c schema.Change) bool {\n\tvar o schema.Object\n\tswitch c := c.(type) {\n\tcase *schema.AddTable:\n\t\treturn slices.ContainsFunc(refs, func(o schema.Object) bool {\n\t\t\tt, ok := o.(*schema.Table)\n\t\t\treturn ok && SameTable(c.T, t)\n\t\t})\n\tcase *schema.ModifyTable:\n\t\treturn slices.ContainsFunc(refs, func(o schema.Object) bool {\n\t\t\tt, ok := o.(*schema.Table)\n\t\t\treturn ok && SameTable(c.T, t)\n\t\t})\n\tcase *schema.AddView:\n\t\treturn slices.ContainsFunc(refs, func(o schema.Object) bool {\n\t\t\tv, ok := o.(*schema.View)\n\t\t\treturn ok && SameView(c.V, v)\n\t\t})\n\tcase *schema.ModifyView:\n\t\treturn slices.ContainsFunc(refs, func(o schema.Object) bool {\n\t\t\tv, ok := o.(*schema.View)\n\t\t\treturn ok && SameView(c.To, v)\n\t\t})\n\tcase *schema.AddObject:\n\t\to = c.O\n\tcase *schema.AddTrigger:\n\t\to = c.T\n\t// Check functions and procedures by\n\t// names as they might have overloads.\n\tcase *schema.AddFunc:\n\t\treturn slices.ContainsFunc(refs, func(o schema.Object) bool {\n\t\t\tf, ok := o.(*schema.Func)\n\t\t\treturn ok && c.F.Name == f.Name && SameSchema(c.F.Schema, f.Schema)\n\t\t})\n\tcase *schema.AddProc:\n\t\treturn slices.ContainsFunc(refs, func(o schema.Object) bool {\n\t\t\tf, ok := o.(*schema.Proc)\n\t\t\treturn ok && c.P.Name == f.Name && SameSchema(c.P.Schema, f.Schema)\n\t\t})\n\tdefault:\n\t\treturn false\n\t}\n\treturn slices.Contains(refs, o)\n}\n\n// refTo reports if the given foreign keys reference the given table.\nfunc refTo(fks []*schema.ForeignKey, to *schema.Table) bool {\n\treturn slices.ContainsFunc(fks, func(fk *schema.ForeignKey) bool {\n\t\treturn SameTable(fk.RefTable, to)\n\t})\n}\n\n// typeDependsOnT reports if the declaration of type \"t\" depends on the table.\nfunc typeDependsOnT(t schema.Type, tt *schema.Table) bool {\n\trt, ok := schema.UnderlyingType(t).(RowTyper)\n\tif !ok {\n\t\treturn false\n\t}\n\trowT := rt.RowTypeT()\n\treturn rowT != nil && SameTable(rowT, tt)\n}\n\n// SameView reports if the two objects represent the same view.\nfunc SameView(v1, v2 *schema.View) bool {\n\tif v1 == nil || v2 == nil {\n\t\treturn v1 == v2\n\t}\n\treturn v1.Name == v2.Name && SameSchema(v1.Schema, v2.Schema)\n}\n\n// SameTable reports if the two objects represent the same table.\nfunc SameTable(t1, t2 *schema.Table) bool {\n\tif t1 == nil || t2 == nil {\n\t\treturn t1 == t2\n\t}\n\treturn t1.Name == t2.Name && SameSchema(t1.Schema, t2.Schema)\n}\n\n// SameSchema reports if the given schemas are the same.\n// Objects can be different as they might reside in two\n// different states (current and desired).\nfunc SameSchema(s1, s2 *schema.Schema) bool {\n\tif s1 == nil || s2 == nil {\n\t\treturn s1 == s2\n\t}\n\treturn s1.Name == s2.Name\n}\n"
  },
  {
    "path": "sql/internal/sqlx/plan_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlx\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDetachCycles(t *testing.T) {\n\tusers := &schema.Table{\n\t\tName: \"users\",\n\t\tColumns: []*schema.Column{\n\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\"}},\n\t\t\t{Name: \"workplace_id\", Type: &schema.ColumnType{Raw: \"bigint\", Null: true}},\n\t\t},\n\t}\n\tworkplaces := &schema.Table{\n\t\tName: \"workplaces\",\n\t\tColumns: []*schema.Column{\n\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\"}},\n\t\t\t{Name: \"owner_id\", Type: &schema.ColumnType{Raw: \"bigint\", Null: true}},\n\t\t},\n\t}\n\tusers.ForeignKeys = []*schema.ForeignKey{\n\t\t{Symbol: \"workplace\", Table: users, Columns: users.Columns[1:2], RefTable: workplaces, RefColumns: workplaces.Columns[:1]},\n\t}\n\tchanges := []schema.Change{&schema.AddTable{T: workplaces}, &schema.AddTable{T: users}}\n\tplanned, err := DetachCycles(changes)\n\trequire.NoError(t, err)\n\trequire.Equal(t, changes, planned)\n\n\tdeletion := []schema.Change{&schema.DropTable{T: users}, &schema.DropTable{T: workplaces}}\n\tplanned, err = DetachCycles(deletion)\n\trequire.NoError(t, err)\n\trequire.Equal(t, deletion, planned)\n\n\t// Create a circular reference.\n\tworkplaces.ForeignKeys = []*schema.ForeignKey{\n\t\t{Symbol: \"owner\", Table: workplaces, Columns: workplaces.Columns[1:], RefTable: users, RefColumns: users.Columns[:1]},\n\t}\n\t// Add a self-ref foreign-key.\n\tusers.Columns = append(users.Columns, &schema.Column{Name: \"spouse_id\", Type: &schema.ColumnType{Raw: \"bigint\", Null: true}})\n\tusers.ForeignKeys = append(users.ForeignKeys, &schema.ForeignKey{Symbol: \"spouse\", Table: users, Columns: users.Columns[2:], RefTable: users, RefColumns: users.Columns[:1]})\n\n\tplanned, err = DetachCycles(changes)\n\trequire.NoError(t, err)\n\trequire.Len(t, planned, 4)\n\trequire.Empty(t, planned[0].(*schema.AddTable).T.ForeignKeys)\n\trequire.NotEmpty(t, planned[1].(*schema.AddTable).T.ForeignKeys)\n\trequire.Equal(t, &schema.ModifyTable{\n\t\tT: workplaces,\n\t\tChanges: []schema.Change{\n\t\t\t&schema.AddForeignKey{\n\t\t\t\tF: &schema.ForeignKey{Symbol: \"owner\", Table: workplaces, Columns: workplaces.Columns[1:], RefTable: users, RefColumns: users.Columns[:1]},\n\t\t\t},\n\t\t},\n\t}, planned[2])\n\trequire.Equal(t, &schema.ModifyTable{\n\t\tT: users,\n\t\tChanges: []schema.Change{\n\t\t\t&schema.AddForeignKey{\n\t\t\t\tF: &schema.ForeignKey{Symbol: \"workplace\", Table: users, Columns: users.Columns[1:2], RefTable: workplaces, RefColumns: workplaces.Columns[:1]},\n\t\t\t},\n\t\t},\n\t}, planned[3])\n\n\tplanned, err = DetachCycles(deletion)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &schema.ModifyTable{\n\t\tT: users,\n\t\tChanges: []schema.Change{\n\t\t\t&schema.DropForeignKey{\n\t\t\t\tF: &schema.ForeignKey{Symbol: \"workplace\", Table: users, Columns: users.Columns[1:2], RefTable: workplaces, RefColumns: workplaces.Columns[:1]},\n\t\t\t},\n\t\t},\n\t}, planned[0])\n\trequire.Equal(t, &schema.ModifyTable{\n\t\tT: workplaces,\n\t\tChanges: []schema.Change{\n\t\t\t&schema.DropForeignKey{\n\t\t\t\tF: &schema.ForeignKey{Symbol: \"owner\", Table: workplaces, Columns: workplaces.Columns[1:], RefTable: users, RefColumns: users.Columns[:1]},\n\t\t\t},\n\t\t},\n\t}, planned[1])\n\tusers.ForeignKeys = nil\n\tworkplaces.ForeignKeys = nil\n\trequire.Equal(t, deletion, planned[2:])\n\n\t// Delete associated table and foreign-key.\n\tusers.AddForeignKeys(\n\t\tschema.NewForeignKey(\"workplace\").AddColumns(users.Columns[1:2]...).SetRefTable(workplaces).AddRefColumns(workplaces.Columns[:1]...),\n\t)\n\tchanges = []schema.Change{&schema.DropTable{T: workplaces}, &schema.ModifyTable{\n\t\tT: users,\n\t\tChanges: []schema.Change{\n\t\t\t&schema.DropForeignKey{F: users.ForeignKeys[0]},\n\t\t},\n\t}}\n\tplanned, err = DetachCycles(changes)\n\trequire.NoError(t, err)\n\trequire.Equal(t, []schema.Change{changes[1], changes[0]}, planned)\n}\n\nfunc TestConsistentOrder(t *testing.T) {\n\tnewT := func(n string) *schema.Table { return schema.NewTable(n).AddColumns(schema.NewIntColumn(\"id\", \"int\")) }\n\tt1, t2, t3 := newT(\"t1\"), newT(\"t2\"), newT(\"t3\")\n\tt2.AddForeignKeys(schema.NewForeignKey(\"t1\").AddColumns(t2.Columns[0]).SetRefTable(t1).AddRefColumns(t1.Columns[0]))\n\tt3.AddForeignKeys(schema.NewForeignKey(\"t1\").AddColumns(t3.Columns[0]).SetRefTable(t1).AddRefColumns(t1.Columns[0]))\n\torder := func() string {\n\t\tplanned, err := DetachCycles([]schema.Change{\n\t\t\t&schema.AddTable{T: t1},\n\t\t\t&schema.AddTable{T: t2},\n\t\t\t&schema.AddTable{T: t3},\n\t\t})\n\t\trequire.NoError(t, err)\n\t\treturn fmt.Sprintf(\"%s,%s,%s\", planned[0].(*schema.AddTable).T.Name, planned[1].(*schema.AddTable).T.Name, planned[2].(*schema.AddTable).T.Name)\n\t}\n\tv := order()\n\tfor i := 0; i < 100; i++ {\n\t\trequire.Equal(t, v, order(), \"inconsistent order\")\n\t}\n}\n\nfunc TestCheckChangesScope(t *testing.T) {\n\terr := CheckChangesScope(migrate.PlanOptions{}, []schema.Change{\n\t\t&schema.AddSchema{},\n\t})\n\trequire.EqualError(t, err, \"*schema.AddSchema is not allowed when migration plan is scoped to one schema\")\n\terr = CheckChangesScope(migrate.PlanOptions{}, []schema.Change{\n\t\t&schema.ModifySchema{\n\t\t\tS: schema.New(\"s1\"),\n\t\t\tChanges: []schema.Change{\n\t\t\t\t&schema.AddAttr{A: &schema.Collation{V: \"utf8\"}},\n\t\t\t},\n\t\t},\n\t})\n\trequire.EqualError(t, err, \"*schema.ModifySchema is not allowed when migration plan is scoped to one schema\")\n\terr = CheckChangesScope(migrate.PlanOptions{}, []schema.Change{\n\t\t&schema.DropSchema{},\n\t})\n\trequire.EqualError(t, err, \"*schema.DropSchema is not allowed when migration plan is scoped to one schema\")\n\terr = CheckChangesScope(migrate.PlanOptions{}, []schema.Change{\n\t\t&schema.AddTable{T: schema.NewTable(\"users\").SetSchema(schema.New(\"s1\"))},\n\t\t&schema.AddTable{T: schema.NewTable(\"users\").SetSchema(schema.New(\"s2\"))},\n\t})\n\trequire.EqualError(t, err, \"found 2 schemas when migration plan is scoped to one: [\\\"s1\\\" \\\"s2\\\"]\")\n}\n\nfunc TestSameTable(t *testing.T) {\n\tt1 := schema.NewTable(\"t1\")\n\trequire.True(t, SameTable(t1, t1))\n\trequire.True(t, SameTable(t1, schema.NewTable(\"t1\")), \"same copy\")\n\trequire.False(t, SameTable(t1, schema.NewTable(\"t2\")))\n\n\tt1.SetSchema(schema.New(\"public\"))\n\trequire.True(t, SameTable(t1, t1))\n\trequire.True(t, SameTable(t1, schema.NewTable(\"t1\").SetSchema(schema.New(\"public\"))), \"same copy\")\n\trequire.False(t, SameTable(t1, schema.NewTable(\"t1\")))\n\trequire.False(t, SameTable(t1, schema.NewTable(\"t1\").SetSchema(schema.New(\"private\"))))\n}\n\nfunc TestSameView(t *testing.T) {\n\tv1 := schema.NewView(\"v1\", \"\")\n\trequire.True(t, SameView(v1, v1))\n\trequire.True(t, SameView(v1, schema.NewView(\"v1\", \"\")), \"same copy\")\n\trequire.False(t, SameView(v1, schema.NewView(\"v2\", \"\")))\n\n\tv1.SetSchema(schema.New(\"public\"))\n\trequire.True(t, SameView(v1, v1))\n\trequire.True(t, SameView(v1, schema.NewView(\"v1\", \"\").SetSchema(schema.New(\"public\"))), \"same copy\")\n\trequire.False(t, SameView(v1, schema.NewView(\"v1\", \"\")))\n\trequire.False(t, SameView(v1, schema.NewView(\"v1\", \"\").SetSchema(schema.New(\"private\"))))\n}\n\nfunc TestSortDropTables_WithFK(t *testing.T) {\n\tt1 := schema.NewTable(\"t1\").AddColumns(schema.NewColumn(\"c1\"))\n\tt2 := schema.NewTable(\"t2\").AddColumns(schema.NewColumn(\"c1\"), schema.NewColumn(\"c2\"))\n\tt2.AddForeignKeys(\n\t\tschema.NewForeignKey(\"FK_t2_t1\").\n\t\t\tAddColumns(t2.Columns[1]).\n\t\t\tAddRefColumns(t1.Columns[0]).\n\t\t\tSetRefTable(t1),\n\t)\n\tt1.Triggers = []*schema.Trigger{\n\t\t{Table: t1, Deps: []schema.Object{t2}},\n\t}\n\tchanges := []schema.Change{&schema.DropTable{T: t2}, &schema.DropTable{T: t1}}\n\trequire.Equal(t, []schema.Change{changes[0], changes[1]}, SortChanges(changes, nil))\n\tchanges = []schema.Change{&schema.DropTable{T: t1}, &schema.DropTable{T: t2}}\n\trequire.Equal(t, []schema.Change{changes[1], changes[0]}, SortChanges(changes, nil))\n}\n"
  },
  {
    "path": "sql/internal/sqlx/sqlx.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlx\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"ariga.io/atlas/sql/schema\"\n)\n\ntype (\n\t// ExecQueryCloser is the interface that groups\n\t// Close with the schema.ExecQuerier methods.\n\tExecQueryCloser interface {\n\t\tschema.ExecQuerier\n\t\tio.Closer\n\t}\n\tnopCloser struct {\n\t\tschema.ExecQuerier\n\t}\n)\n\n// Close implements the io.Closer interface.\nfunc (nopCloser) Close() error { return nil }\n\n// SingleConn returns a closable single connection from the given ExecQuerier.\n// If the ExecQuerier is already bound to a single connection (e.g. Tx, Conn),\n// the connection will return as-is with a NopCloser.\nfunc SingleConn(ctx context.Context, conn schema.ExecQuerier) (ExecQueryCloser, error) {\n\t// A standard sql.DB or a wrapper of it.\n\tif opener, ok := conn.(interface {\n\t\tConn(context.Context) (*sql.Conn, error)\n\t}); ok {\n\t\treturn opener.Conn(ctx)\n\t}\n\t// Tx and Conn are bounded to a single connection.\n\t// We use sql/driver.Tx to cover also custom Tx structs.\n\t_, ok1 := conn.(driver.Tx)\n\t_, ok2 := conn.(*sql.Conn)\n\tif ok1 || ok2 {\n\t\treturn nopCloser{ExecQuerier: conn}, nil\n\t}\n\treturn nil, fmt.Errorf(\"cannot obtain a single connection from %T\", conn)\n}\n\n// ValidString reports if the given string is not null and valid.\nfunc ValidString(s sql.NullString) bool {\n\treturn s.Valid && s.String != \"\" && strings.ToLower(s.String) != \"null\"\n}\n\n// ScanOne scans one record and closes the rows at the end.\nfunc ScanOne(rows *sql.Rows, dest ...any) error {\n\tdefer rows.Close()\n\tif !rows.Next() {\n\t\treturn sql.ErrNoRows\n\t}\n\tif err := rows.Scan(dest...); err != nil {\n\t\treturn err\n\t}\n\treturn rows.Err()\n}\n\n// ScanNullBool scans one sql.NullBool record and closes the rows at the end.\nfunc ScanNullBool(rows *sql.Rows) (sql.NullBool, error) {\n\tvar b sql.NullBool\n\treturn b, ScanOne(rows, &b)\n}\n\ntype (\n\t// ScanStringer groups the fmt.Stringer and sql.Scanner interfaces.\n\tScanStringer interface {\n\t\tfmt.Stringer\n\t\tsql.Scanner\n\t}\n\t// nullString is a sql.NullString that implements the ScanStringer interface.\n\tnullString struct{ sql.NullString }\n)\n\nfunc (s nullString) String() string    { return s.NullString.String }\nfunc (s *nullString) Scan(v any) error { return s.NullString.Scan(v) }\n\n// SchemaFKs scans the rows and adds the foreign-key to the schema table.\n// Reference elements are added as stubs and should be linked manually by the\n// caller.\nfunc SchemaFKs(s *schema.Schema, rows *sql.Rows) error {\n\treturn TypedSchemaFKs[*nullString](s, rows)\n}\n\n// FKAttrScanner allows extending foreign-keys\n// scanning with extra attributes.\ntype FKAttrScanner struct {\n\tColumns  func() []any\n\tScanFunc func(*schema.ForeignKey, []any) error\n}\n\n// TypedSchemaFKs is a version of SchemaFKs that allows to specify the type of\n// used to scan update and delete actions from the database.\nfunc TypedSchemaFKs[T ScanStringer](s *schema.Schema, rows *sql.Rows, attr ...*FKAttrScanner) error {\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tupdateAction, deleteAction                                   = V(new(T)), V(new(T))\n\t\t\tname, table, column, tSchema, refTable, refColumn, refSchema string\n\t\t\tcolumns                                                      = []any{\n\t\t\t\t&name, &table, &column, &tSchema, &refTable, &refColumn, &refSchema, &updateAction, &deleteAction,\n\t\t\t}\n\t\t\torigin = len(columns)\n\t\t)\n\t\t// Allows to scan extra attributes.\n\t\tswitch {\n\t\tcase len(attr) > 1:\n\t\t\treturn fmt.Errorf(\"unexpected number of attributes scanners: %d\", len(attr))\n\t\tcase len(attr) == 1:\n\t\t\tcolumns = append(columns, attr[0].Columns()...)\n\t\t}\n\t\tif err := rows.Scan(columns...); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tt, ok := s.Table(table)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"table %q was not found in schema\", table)\n\t\t}\n\t\tfk, ok := t.ForeignKey(name)\n\t\tif !ok {\n\t\t\tfk = &schema.ForeignKey{\n\t\t\t\tSymbol:   name,\n\t\t\t\tTable:    t,\n\t\t\t\tRefTable: t,\n\t\t\t\tOnUpdate: schema.ReferenceOption(updateAction.String()),\n\t\t\t\tOnDelete: schema.ReferenceOption(deleteAction.String()),\n\t\t\t}\n\t\t\tswitch {\n\t\t\t// Self reference.\n\t\t\tcase tSchema == refSchema && refTable == table:\n\t\t\t// Reference to the same schema.\n\t\t\tcase tSchema == refSchema && refTable != table:\n\t\t\t\tif fk.RefTable, ok = s.Table(refTable); !ok {\n\t\t\t\t\tfk.RefTable = &schema.Table{Name: refTable, Schema: s}\n\t\t\t\t}\n\t\t\t// Reference to an external schema.\n\t\t\tcase tSchema != refSchema:\n\t\t\t\tfk.RefTable = &schema.Table{Name: refTable, Schema: &schema.Schema{Name: refSchema}}\n\t\t\t}\n\t\t\tt.ForeignKeys = append(t.ForeignKeys, fk)\n\t\t}\n\t\tc, ok := t.Column(column)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"column %q was not found for fk %q\", column, fk.Symbol)\n\t\t}\n\t\t// Rows are ordered by ORDINAL_POSITION that specifies\n\t\t// the position of the column in the FK definition.\n\t\tif _, ok := fk.Column(c.Name); !ok {\n\t\t\tfk.Columns = append(fk.Columns, c)\n\t\t\tc.ForeignKeys = append(c.ForeignKeys, fk)\n\t\t}\n\t\t// Stub referenced columns or link if it's a self-reference.\n\t\tvar rc *schema.Column\n\t\tif fk.Table != fk.RefTable {\n\t\t\trc = &schema.Column{Name: refColumn}\n\t\t} else if c, ok := t.Column(refColumn); ok {\n\t\t\trc = c\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"referenced column %q was not found for fk %q\", refColumn, fk.Symbol)\n\t\t}\n\t\tif _, ok := fk.RefColumn(rc.Name); !ok {\n\t\t\tfk.RefColumns = append(fk.RefColumns, rc)\n\t\t}\n\t\tif len(attr) == 1 {\n\t\t\tif err := attr[0].ScanFunc(fk, columns[origin:]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// LinkSchemaTables links foreign-key stub tables/columns to actual elements.\nfunc LinkSchemaTables(schemas []*schema.Schema) {\n\tbyName := make(map[string]map[string]*schema.Table)\n\tfor _, s := range schemas {\n\t\tbyName[s.Name] = make(map[string]*schema.Table)\n\t\tfor _, t := range s.Tables {\n\t\t\tt.Schema = s\n\t\t\tbyName[s.Name][t.Name] = t\n\t\t}\n\t}\n\tfor _, s := range schemas {\n\t\tfor _, t := range s.Tables {\n\t\t\tfor _, fk := range t.ForeignKeys {\n\t\t\t\trs, ok := byName[fk.RefTable.Schema.Name]\n\t\t\t\tif !ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tref, ok := rs[fk.RefTable.Name]\n\t\t\t\tif !ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfk.RefTable = ref\n\t\t\t\tfor i, c := range fk.RefColumns {\n\t\t\t\t\trc, ok := ref.Column(c.Name)\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tfk.RefColumns[i] = rc\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ValuesEqual checks if the 2 string slices are equal (including their order).\nfunc ValuesEqual(v1, v2 []string) bool {\n\tif len(v1) != len(v2) {\n\t\treturn false\n\t}\n\tfor i := range v1 {\n\t\tif v1[i] != v2[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// ModeInspectSchema returns the InspectMode or its default.\nfunc ModeInspectSchema(o *schema.InspectOptions) schema.InspectMode {\n\tif o != nil && o.Mode != 0 {\n\t\treturn o.Mode\n\t}\n\treturn modeSchemaOrAll(V(o).Exclude, \"*\")\n}\n\n// ModeInspectRealm returns the InspectMode or its default.\nfunc ModeInspectRealm(o *schema.InspectRealmOption) schema.InspectMode {\n\tif o != nil && o.Mode != 0 {\n\t\treturn o.Mode\n\t}\n\treturn modeSchemaOrAll(V(o).Exclude, \"*.*\")\n}\n\n// modeSchemaOrAll returns the inspect mode based on the exclude patterns.\nfunc modeSchemaOrAll(exclude []string, match string) schema.InspectMode {\n\tif slices.Contains(exclude, match) {\n\t\treturn schema.InspectSchemas\n\t}\n\treturn schema.InspectSchemas | schema.InspectTables | schema.InspectViews | schema.InspectFuncs |\n\t\tschema.InspectTypes | schema.InspectObjects | schema.InspectTriggers\n}\n\n// A Builder provides a syntactic sugar API for writing SQL statements.\ntype Builder struct {\n\tbytes.Buffer\n\tQuoteOpening byte    // quoting identifiers\n\tQuoteClosing byte    // quoting identifiers\n\tSchema       *string // schema qualifier\n\tIndent       string  // indentation string\n\tlevel        int     // current indentation level\n}\n\n// P writes a list of phrases to the builder separated and\n// suffixed with whitespace.\nfunc (b *Builder) P(phrases ...string) *Builder {\n\tfor _, p := range phrases {\n\t\tif p == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif b.Len() > 0 && !slices.Contains([]byte{' ', '(', '\\n'}, b.lastByte()) {\n\t\t\tb.WriteByte(' ')\n\t\t}\n\t\tb.WriteString(p)\n\t\tif p[len(p)-1] != ' ' {\n\t\t\tb.WriteByte(' ')\n\t\t}\n\t}\n\treturn b\n}\n\n// Int64 writes the given value to the builder in base 10.\nfunc (b *Builder) Int64(v int64) *Builder {\n\treturn b.P(strconv.FormatInt(v, 10))\n}\n\n// Ident writes the given string quoted as an SQL identifier.\nfunc (b *Builder) Ident(s string) *Builder {\n\tif s != \"\" {\n\t\tb.WriteByte(b.QuoteOpening)\n\t\tb.WriteString(s)\n\t\tb.WriteByte(b.QuoteClosing)\n\t\tb.WriteByte(' ')\n\t}\n\treturn b\n}\n\n// View writes the view identifier to the builder, prefixed\n// with the schema name if exists.\nfunc (b *Builder) View(v *schema.View) *Builder {\n\treturn b.mayQualify(v.Schema, v.Name)\n}\n\n// Table writes the table identifier to the builder, prefixed\n// with the schema name if exists.\nfunc (b *Builder) Table(t *schema.Table) *Builder {\n\treturn b.mayQualify(t.Schema, t.Name)\n}\n\n// RefTable writes the referenced/parent table identifier to the builder.\n// Unlike the Table method, RefTable prefix the table with its schema qualifier\n// if the \"Schema\" is set to nil, or if the schema is set to empty (schema-scope),\n// and the parent table is in a different schema. For example:\n//\n//\tCREATE TABLE child (\n//\t\tid INT PRIMARY KEY,\n//\t\tparent_id1 INT REFERENCES other1.parent(id)\n//\t\tparent_id2 INT REFERENCES other2.parent(id)\n//\t);\n//\n// This case is possible only if the child table (and its schema) was loaded with\n// baseline schema (contains other1, other2) or with external references to resources\n// not managed by this scope.\nfunc (b *Builder) RefTable(childT, parentT *schema.Table) *Builder {\n\t// Default schema-scope config (no schema qualifier), both schemas are known, and parent table resides in a different schema.\n\tif b.Schema != nil && *b.Schema == \"\" && V(childT.Schema).Name != \"\" && V(parentT.Schema).Name != \"\" && !SameSchema(childT.Schema, parentT.Schema) {\n\t\tb.Ident(parentT.Schema.Name)\n\t\tb.rewriteLastByte('.')\n\t\tb.Ident(parentT.Name)\n\t\treturn b\n\t}\n\treturn b.Table(parentT)\n}\n\n// TableColumn writes the table's resource identifier to the builder, prefixed\n// with the schema name if exists.\nfunc (b *Builder) TableColumn(t *schema.Table, c *schema.Column) *Builder {\n\treturn b.mayQualify(t.Schema, t.Name, c.Name)\n}\n\n// Func writes the function identifier to the builder, prefixed\n// with the schema name if exists.\nfunc (b *Builder) Func(f *schema.Func) *Builder {\n\treturn b.mayQualify(f.Schema, f.Name)\n}\n\n// FuncCall writes the function identifier to the builder as a function call,\nfunc (b *Builder) FuncCall(f *schema.Func, args ...string) *Builder {\n\tb.Func(f).rewriteLastByte('(')\n\tb.MapComma(args, func(i int, b *Builder) {\n\t\tb.WriteString(args[i])\n\t})\n\tb.WriteByte(')')\n\treturn b\n}\n\n// Proc writes the procedure identifier to the builder, prefixed\n// with the schema name if exists.\nfunc (b *Builder) Proc(p *schema.Proc) *Builder {\n\treturn b.mayQualify(p.Schema, p.Name)\n}\n\n// ProcCall writes the procedure identifier to the builder as a procedure call,\nfunc (b *Builder) ProcCall(p *schema.Proc, args ...string) *Builder {\n\tb.Proc(p).rewriteLastByte('(')\n\tb.MapComma(args, func(i int, b *Builder) {\n\t\tb.WriteString(args[i])\n\t})\n\tb.WriteByte(')')\n\treturn b\n}\n\n// TableResource writes the table resource identifier to the builder, prefixed\n// with the schema name if exists.\nfunc (b *Builder) TableResource(t *schema.Table, r any) *Builder {\n\tswitch c := r.(type) {\n\tcase *schema.Column:\n\t\treturn b.TableColumn(t, c)\n\tcase *schema.Index:\n\t\treturn b.mayQualify(t.Schema, t.Name, c.Name)\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unexpected table resource: %T\", r))\n\t}\n}\n\n// ViewResource writes the view resource identifier to the builder, prefixed\n// with the schema name if exists.\nfunc (b *Builder) ViewResource(v *schema.View, r any) *Builder {\n\tswitch c := r.(type) {\n\tcase *schema.Column:\n\t\treturn b.mayQualify(v.Schema, v.Name, c.Name)\n\tcase *schema.Index:\n\t\treturn b.mayQualify(v.Schema, v.Name, c.Name)\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unexpected view resource: %T\", r))\n\t}\n}\n\n// SchemaResource writes the schema resource identifier to the builder, prefixed\n// with the schema name if exists.\nfunc (b *Builder) SchemaResource(s *schema.Schema, name string) *Builder {\n\treturn b.mayQualify(s, name)\n}\n\nfunc (b *Builder) mayQualify(s *schema.Schema, top string, children ...string) *Builder {\n\tswitch {\n\t// Custom qualifier.\n\tcase b.Schema != nil:\n\t\t// Empty means skip prefix.\n\t\tif *b.Schema != \"\" {\n\t\t\tb.Ident(*b.Schema)\n\t\t\tb.rewriteLastByte('.')\n\t\t}\n\t// Default schema qualifier.\n\tcase s != nil && s.Name != \"\":\n\t\tb.Ident(s.Name)\n\t\tb.rewriteLastByte('.')\n\t}\n\tb.Ident(top)\n\tfor _, ident := range children {\n\t\tb.rewriteLastByte('.')\n\t\tb.Ident(ident)\n\t}\n\treturn b\n}\n\n// IndentIn adds one indentation in.\nfunc (b *Builder) IndentIn() *Builder {\n\tb.level++\n\treturn b\n}\n\n// IndentOut removed one indentation level.\nfunc (b *Builder) IndentOut() *Builder {\n\tb.level--\n\treturn b\n}\n\n// NL adds line break and prefix the new line with\n// indentation in case indentation is enabled.\nfunc (b *Builder) NL() *Builder {\n\tif b.Indent != \"\" {\n\t\tif b.lastByte() == ' ' {\n\t\t\tb.rewriteLastByte('\\n')\n\t\t} else {\n\t\t\tb.WriteByte('\\n')\n\t\t}\n\t\tb.WriteString(strings.Repeat(b.Indent, b.level))\n\t}\n\treturn b\n}\n\n// Comma writes a comma in case the buffer is not empty, or\n// replaces the last char if it is a whitespace.\nfunc (b *Builder) Comma() *Builder {\n\tswitch {\n\tcase b.Len() == 0:\n\tcase b.lastByte() == ' ':\n\t\tb.rewriteLastByte(',')\n\t\tb.WriteByte(' ')\n\tdefault:\n\t\tb.WriteString(\", \")\n\t}\n\treturn b\n}\n\n// MapComma maps the slice x using the function f and joins the result with\n// a comma separating between the written elements.\nfunc (b *Builder) MapComma(x any, f func(i int, b *Builder)) *Builder {\n\ts := reflect.ValueOf(x)\n\tfor i := 0; i < s.Len(); i++ {\n\t\tif i > 0 {\n\t\t\tb.Comma()\n\t\t}\n\t\tf(i, b)\n\t}\n\treturn b\n}\n\n// Quote wraps the given function with a single quote and a prefix\nfunc (b *Builder) Quote(prefix string, fn func(b *Builder)) *Builder {\n\tb.WriteString(prefix)\n\tb.WriteByte('\\'')\n\tfn(b)\n\tif b.lastByte() != ' ' {\n\t\tb.WriteByte('\\'')\n\t} else {\n\t\tb.rewriteLastByte('\\'')\n\t}\n\treturn b\n}\n\n// MapIndent is like MapComma, but writes a new line before each element.\nfunc (b *Builder) MapIndent(x any, f func(i int, b *Builder)) *Builder {\n\treturn b.MapComma(x, func(i int, b *Builder) {\n\t\tf(i, b.NL())\n\t})\n}\n\n// MapCommaErr is like MapComma, but returns an error if f returns an error.\nfunc (b *Builder) MapCommaErr(x any, f func(i int, b *Builder) error) error {\n\ts := reflect.ValueOf(x)\n\tfor i := 0; i < s.Len(); i++ {\n\t\tif i > 0 {\n\t\t\tb.Comma()\n\t\t}\n\t\tif err := f(i, b); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// MapIndentErr is like MapCommaErr, but writes a new line before each element.\nfunc (b *Builder) MapIndentErr(x any, f func(i int, b *Builder) error) error {\n\treturn b.MapCommaErr(x, func(i int, b *Builder) error {\n\t\treturn f(i, b.NL())\n\t})\n}\n\n// Wrap wraps the written string with parentheses.\nfunc (b *Builder) Wrap(f func(b *Builder)) *Builder {\n\tb.WriteByte('(')\n\tf(b)\n\tif b.lastByte() != ' ' {\n\t\tb.WriteByte(')')\n\t} else {\n\t\tb.rewriteLastByte(')')\n\t}\n\treturn b\n}\n\n// WrapErr wraps the written string with parentheses\nfunc (b *Builder) WrapErr(f func(b *Builder) error) error {\n\tvar err error\n\tb.Wrap(func(b *Builder) { err = f(b) })\n\treturn err\n}\n\n// WrapIndent is like Wrap but with extra level of indentation.\nfunc (b *Builder) WrapIndent(f func(b *Builder)) *Builder {\n\treturn b.Wrap(func(b *Builder) {\n\t\tb.IndentIn()\n\t\tf(b)\n\t\tb.IndentOut()\n\t\tb.NL()\n\t})\n}\n\n// WrapIndentErr is like WrapErr but with extra level of indentation.\nfunc (b *Builder) WrapIndentErr(f func(b *Builder) error) error {\n\tvar err error\n\tb.Wrap(func(b *Builder) {\n\t\tb.IndentIn()\n\t\terr = f(b)\n\t\tb.IndentOut()\n\t\tb.NL()\n\t})\n\treturn err\n}\n\n// Clone returns a duplicate of the builder.\nfunc (b *Builder) Clone() *Builder {\n\treturn &Builder{\n\t\tQuoteOpening: b.QuoteOpening,\n\t\tQuoteClosing: b.QuoteClosing,\n\t\tBuffer:       *bytes.NewBufferString(b.Buffer.String()),\n\t}\n}\n\n// String overrides the Buffer.String method and ensure no spaces pad the returned statement.\nfunc (b *Builder) String() string {\n\treturn strings.TrimSpace(b.Buffer.String())\n}\n\nfunc (b *Builder) lastByte() byte {\n\tif b.Len() == 0 {\n\t\treturn 0\n\t}\n\tbuf := b.Buffer.Bytes()\n\treturn buf[len(buf)-1]\n}\n\nfunc (b *Builder) rewriteLastByte(c byte) {\n\tif b.Len() == 0 {\n\t\treturn\n\t}\n\tbuf := b.Buffer.Bytes()\n\tbuf[len(buf)-1] = c\n}\n\n// IsQuoted reports if the given string is quoted with one of the given quotes (e.g. ', \", `).\nfunc IsQuoted(s string, q ...byte) bool {\n\tlast := len(s) - 1\n\tif last < 1 {\n\t\treturn false\n\t}\nTop:\n\tfor _, quote := range q {\n\t\tif s[0] != quote || s[last] != quote {\n\t\t\tcontinue\n\t\t}\n\t\tfor i := 1; i < last-1; i++ {\n\t\t\tswitch c := s[i]; {\n\t\t\tcase c == '\\\\', c == quote && s[i+1] == quote:\n\t\t\t\ti++\n\t\t\t// Accept only escaped quotes and reject otherwise.\n\t\t\tcase c == quote:\n\t\t\t\tcontinue Top\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n\treturn false\n}\n\n// IsLiteralBool reports if the given string is a valid literal bool.\nfunc IsLiteralBool(s string) bool {\n\t_, err := strconv.ParseBool(s)\n\treturn err == nil\n}\n\n// IsLiteralNumber reports if the given string is a literal number.\nfunc IsLiteralNumber(s string) bool {\n\t// Hex digits.\n\tif strings.HasPrefix(s, \"0x\") || strings.HasPrefix(s, \"0X\") {\n\t\t// Some databases allow odd length hex string.\n\t\t_, err := strconv.ParseUint(s[2:], 16, 64)\n\t\treturn err == nil\n\t}\n\t// Digits with optional exponent.\n\t_, err := strconv.ParseFloat(s, 64)\n\treturn err == nil\n}\n\n// DefaultValue returns the string represents the DEFAULT of a column.\nfunc DefaultValue(c *schema.Column) (string, bool) {\n\tswitch x := schema.UnderlyingExpr(c.Default).(type) {\n\tcase nil:\n\t\treturn \"\", false\n\tcase *schema.Literal:\n\t\treturn x.V, true\n\tcase *schema.RawExpr:\n\t\treturn x.X, true\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unexpected default value type: %T\", x))\n\t}\n}\n\n// MayWrap ensures the given string is wrapped with parentheses.\n// Used by the different drivers to turn strings valid expressions.\nfunc MayWrap(s string) string {\n\tn := len(s) - 1\n\tif len(s) < 2 || s[0] != '(' || s[n] != ')' || !balanced(s[1:n]) {\n\t\treturn \"(\" + s + \")\"\n\t}\n\treturn s\n}\n\nfunc balanced(expr string) bool {\n\treturn ExprLastIndex(expr) == len(expr)-1\n}\n\n// ExprLastIndex scans the first expression in the given string until\n// its end and returns its last index.\nfunc ExprLastIndex(expr string) int {\n\tvar l, r int\n\tfor i := 0; i < len(expr); i++ {\n\tTop:\n\t\tswitch expr[i] {\n\t\tcase '(':\n\t\t\tl++\n\t\tcase ')':\n\t\t\tr++\n\t\t// String or identifier.\n\t\tcase '\\'', '\"', '`':\n\t\t\tfor j := i + 1; j < len(expr); j++ {\n\t\t\t\tswitch expr[j] {\n\t\t\t\tcase '\\\\':\n\t\t\t\t\tj++\n\t\t\t\tcase expr[i]:\n\t\t\t\t\ti = j\n\t\t\t\t\tbreak Top\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Unexpected EOS.\n\t\t\treturn -1\n\t\t}\n\t\t// Balanced parens and we reached EOS or a terminator.\n\t\tif l == r && (i == len(expr)-1 || expr[i+1] == ',') {\n\t\t\treturn i\n\t\t} else if r > l {\n\t\t\treturn -1\n\t\t}\n\t}\n\treturn -1\n}\n\n// ReverseChanges reverses the order of the changes.\nfunc ReverseChanges(c []schema.Change) {\n\tfor i, n := 0, len(c); i < n/2; i++ {\n\t\tc[i], c[n-i-1] = c[n-i-1], c[i]\n\t}\n}\n\n// P returns a pointer to v.\nfunc P[T any](v T) *T {\n\treturn &v\n}\n\n// V returns the value p is pointing to.\n// If p is nil, the zero value is returned.\nfunc V[T any](p *T) (v T) {\n\tif p != nil {\n\t\tv = *p\n\t}\n\treturn\n}\n\n// IsUint reports whether the string represents an unsigned integer.\nfunc IsUint(s string) bool {\n\tfor _, r := range s {\n\t\tif !unicode.IsDigit(r) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "sql/internal/sqlx/sqlx_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage sqlx\n\nimport (\n\t\"slices\"\n\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// sortViewChanges is an optional function to sort to views by their dependencies.\nfunc sortViewChanges(changes []schema.Change) ([]schema.Change, error) {\n\treturn changes, nil // unimplemented.\n}\n\nfunc (*Diff) triggerDiff(_, _ interface {\n\tTrigger(string) (*schema.Trigger, bool)\n}, _, _ []*schema.Trigger, _ *schema.DiffOptions) ([]schema.Change, error) {\n\treturn nil, nil // unimplemented.\n}\n\n// funcDep returns true if f1 depends on f2.\nfunc funcDep(_, _ *schema.Func, _ SortOptions) bool {\n\treturn false // unimplemented.\n}\n\n// procDep returns true if p1 depends on p2.\nfunc procDep(_, _ *schema.Proc, _ SortOptions) bool {\n\treturn false // unimplemented.\n}\n\nfunc tableDepFunc(*schema.Table, *schema.Func, SortOptions) bool {\n\treturn false // unimplemented.\n}\n\nfunc (*Diff) askForColumns(_ *schema.Table, changes []schema.Change, _ *schema.DiffOptions) ([]schema.Change, error) {\n\treturn changes, nil // unimplemented.\n}\n\nfunc (*Diff) askForIndexes(_ string, changes []schema.Change, _ *schema.DiffOptions) ([]schema.Change, error) {\n\treturn changes, nil // unimplemented.\n}\n\nfunc (*Diff) fixRenames(changes schema.Changes) schema.Changes {\n\treturn changes // unimplemented.\n}\n\n// dependsOn reports if the given change depends on the other change.\nfunc dependsOn(c1, c2 schema.Change, _ SortOptions) bool {\n\tif dependOnOf(c1, c2) {\n\t\treturn true\n\t}\n\tswitch c1 := c1.(type) {\n\tcase *schema.DropSchema:\n\t\tswitch c2 := c2.(type) {\n\t\tcase *schema.DropTable:\n\t\t\t// Schema must be dropped after all its tables and references to them.\n\t\t\treturn SameSchema(c1.S, c2.T.Schema) || slices.ContainsFunc(c2.T.ForeignKeys, func(fk *schema.ForeignKey) bool {\n\t\t\t\treturn SameSchema(c1.S, fk.RefTable.Schema)\n\t\t\t})\n\t\tcase *schema.ModifyTable:\n\t\t\treturn SameSchema(c1.S, c2.T.Schema) || slices.ContainsFunc(c2.Changes, func(c schema.Change) bool {\n\t\t\t\tfk, ok := c.(*schema.DropForeignKey)\n\t\t\t\treturn ok && SameSchema(c1.S, fk.F.RefTable.Schema)\n\t\t\t})\n\t\t}\n\tcase *schema.AddTable:\n\t\tswitch c2 := c2.(type) {\n\t\tcase *schema.AddSchema:\n\t\t\treturn c1.T.Schema.Name == c2.S.Name\n\t\tcase *schema.DropTable:\n\t\t\t// Table recreation.\n\t\t\treturn c1.T.Name == c2.T.Name && SameSchema(c1.T.Schema, c2.T.Schema)\n\t\tcase *schema.AddTable:\n\t\t\tif refTo(c1.T.ForeignKeys, c2.T) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif slices.ContainsFunc(c1.T.Columns, func(c *schema.Column) bool {\n\t\t\t\treturn c.Type != nil && typeDependsOnT(c.Type.Type, c2.T)\n\t\t\t}) {\n\t\t\t\treturn true\n\t\t\t}\n\t\tcase *schema.ModifyTable:\n\t\t\tif (c1.T.Name != c2.T.Name || !SameSchema(c1.T.Schema, c2.T.Schema)) && refTo(c1.T.ForeignKeys, c2.T) {\n\t\t\t\treturn true\n\t\t\t}\n\t\tcase *schema.AddObject:\n\t\t\tt, ok := c2.O.(schema.Type)\n\t\t\tif ok && slices.ContainsFunc(c1.T.Columns, func(c *schema.Column) bool {\n\t\t\t\treturn schema.IsType(c.Type.Type, t)\n\t\t\t}) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn depOfAdd(c1.T.Deps, c2)\n\tcase *schema.DropTable:\n\t\t// If it is a drop of a table, the change must occur\n\t\t// after all resources that rely on it will be dropped.\n\t\tswitch c2 := c2.(type) {\n\t\tcase *schema.DropTable:\n\t\t\t// References to this table, must be dropped first.\n\t\t\tif refTo(c2.T.ForeignKeys, c1.T) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif slices.ContainsFunc(c2.T.Columns, func(c *schema.Column) bool {\n\t\t\t\treturn c.Type != nil && typeDependsOnT(c.Type.Type, c1.T)\n\t\t\t}) {\n\t\t\t\treturn true\n\t\t\t}\n\t\tcase *schema.ModifyTable:\n\t\t\tif slices.ContainsFunc(c2.Changes, func(c schema.Change) bool {\n\t\t\t\tswitch c := c.(type) {\n\t\t\t\tcase *schema.DropForeignKey:\n\t\t\t\t\treturn refTo([]*schema.ForeignKey{c.F}, c1.T)\n\t\t\t\tcase *schema.DropColumn:\n\t\t\t\t\treturn c.C.Type != nil && typeDependsOnT(c.C.Type.Type, c1.T)\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t}) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn depOfDrop(c1.T, c2)\n\tcase *schema.ModifyTable:\n\t\tswitch c2 := c2.(type) {\n\t\tcase *schema.AddTable:\n\t\t\t// Table modification relies on its creation.\n\t\t\tif c1.T.Name == c2.T.Name && SameSchema(c1.T.Schema, c2.T.Schema) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\t// Tables need to be created before referencing them.\n\t\t\tif slices.ContainsFunc(c1.Changes, func(c schema.Change) bool {\n\t\t\t\tswitch c := c.(type) {\n\t\t\t\tcase *schema.AddForeignKey:\n\t\t\t\t\treturn refTo([]*schema.ForeignKey{c.F}, c2.T)\n\t\t\t\tcase *schema.AddColumn:\n\t\t\t\t\treturn c.C.Type != nil && typeDependsOnT(c.C.Type.Type, c2.T)\n\t\t\t\tcase *schema.ModifyColumn:\n\t\t\t\t\treturn c.To.Type != nil && typeDependsOnT(c.To.Type.Type, c2.T)\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t}) {\n\t\t\t\treturn true\n\t\t\t}\n\t\tcase *schema.ModifyTable:\n\t\t\tif c1.T != c2.T {\n\t\t\t\taddC := make(map[*schema.Column]bool)\n\t\t\t\tfor _, c := range c2.Changes {\n\t\t\t\t\tif add, ok := c.(*schema.AddColumn); ok {\n\t\t\t\t\t\taddC[add.C] = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn slices.ContainsFunc(c1.Changes, func(c schema.Change) bool {\n\t\t\t\t\tfk, ok := c.(*schema.AddForeignKey)\n\t\t\t\t\treturn ok && refTo([]*schema.ForeignKey{fk.F}, c2.T) && slices.ContainsFunc(fk.F.Columns, func(c *schema.Column) bool { return addC[c] })\n\t\t\t\t})\n\t\t\t}\n\t\tcase *schema.AddObject:\n\t\t\tt, ok := c2.O.(schema.Type)\n\t\t\tif ok && slices.ContainsFunc(c1.Changes, func(c schema.Change) bool {\n\t\t\t\tswitch c := c.(type) {\n\t\t\t\tcase *schema.AddColumn:\n\t\t\t\t\treturn schema.IsType(c.C.Type.Type, t)\n\t\t\t\tcase *schema.ModifyColumn:\n\t\t\t\t\treturn schema.IsType(c.To.Type.Type, t)\n\t\t\t\tdefault:\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn depOfAdd(c1.T.Deps, c2)\n\tcase *schema.DropObject:\n\t\tt, ok := c1.O.(schema.Type)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\t\t// Dropping a type must occur after all its usage were dropped.\n\t\tswitch c2 := c2.(type) {\n\t\tcase *schema.DropTable:\n\t\t\t// Dropping a table also drops its triggers and might depend on the type.\n\t\t\tif slices.ContainsFunc(c2.T.Triggers, func(tg *schema.Trigger) bool {\n\t\t\t\treturn slices.Contains(tg.Deps, c1.O)\n\t\t\t}) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif slices.ContainsFunc(c2.T.Columns, func(c *schema.Column) bool {\n\t\t\t\treturn schema.IsType(c.Type.Type, t)\n\t\t\t}) {\n\t\t\t\treturn true\n\t\t\t}\n\t\tcase *schema.ModifyTable:\n\t\t\treturn slices.ContainsFunc(c2.Changes, func(c schema.Change) bool {\n\t\t\t\td, ok := c.(*schema.DropColumn)\n\t\t\t\treturn ok && schema.IsType(d.C.Type.Type, t)\n\t\t\t})\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "sql/internal/sqlx/sqlx_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlx\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestModeInspectRealm(t *testing.T) {\n\tm := ModeInspectRealm(nil)\n\trequire.True(t, m.Is(schema.InspectSchemas))\n\trequire.True(t, m.Is(schema.InspectTables))\n\n\tm = ModeInspectRealm(&schema.InspectRealmOption{})\n\trequire.True(t, m.Is(schema.InspectSchemas))\n\trequire.True(t, m.Is(schema.InspectTables))\n\n\tm = ModeInspectRealm(&schema.InspectRealmOption{Mode: schema.InspectSchemas})\n\trequire.True(t, m.Is(schema.InspectSchemas))\n\trequire.False(t, m.Is(schema.InspectTables))\n\n\tm = ModeInspectRealm(&schema.InspectRealmOption{Exclude: []string{\"*.*\"}})\n\trequire.Equal(t, schema.InspectSchemas, m)\n\tm = ModeInspectRealm(&schema.InspectRealmOption{Exclude: []string{\"*\"}})\n\trequire.NotEqual(t, schema.InspectSchemas, m)\n\trequire.True(t, m.Is(schema.InspectSchemas))\n\trequire.True(t, m.Is(schema.InspectTables))\n\tm = ModeInspectRealm(&schema.InspectRealmOption{Mode: schema.InspectFuncs, Exclude: []string{\"*.*\"}})\n\trequire.NotEqual(t, schema.InspectSchemas, m)\n\trequire.True(t, m.Is(schema.InspectFuncs))\n\trequire.False(t, m.Is(schema.InspectTables))\n}\n\nfunc TestModeInspectSchema(t *testing.T) {\n\tm := ModeInspectSchema(nil)\n\trequire.True(t, m.Is(schema.InspectSchemas))\n\trequire.True(t, m.Is(schema.InspectTables))\n\n\tm = ModeInspectSchema(&schema.InspectOptions{})\n\trequire.True(t, m.Is(schema.InspectSchemas))\n\trequire.True(t, m.Is(schema.InspectTables))\n\n\tm = ModeInspectSchema(&schema.InspectOptions{Mode: schema.InspectSchemas})\n\trequire.True(t, m.Is(schema.InspectSchemas))\n\trequire.False(t, m.Is(schema.InspectTables))\n\n\tm = ModeInspectSchema(&schema.InspectOptions{Exclude: []string{\"*\"}})\n\trequire.Equal(t, schema.InspectSchemas, m)\n\tm = ModeInspectSchema(&schema.InspectOptions{Exclude: []string{\"*.*\"}})\n\trequire.NotEqual(t, schema.InspectSchemas, m)\n\trequire.True(t, m.Is(schema.InspectSchemas))\n\trequire.True(t, m.Is(schema.InspectTables))\n\tm = ModeInspectSchema(&schema.InspectOptions{Mode: schema.InspectFuncs, Exclude: []string{\"*\"}})\n\trequire.NotEqual(t, schema.InspectSchemas, m)\n\trequire.True(t, m.Is(schema.InspectFuncs))\n\trequire.False(t, m.Is(schema.InspectTables))\n}\n\nfunc TestBuilder(t *testing.T) {\n\tvar (\n\t\tb       = &Builder{QuoteOpening: '\"', QuoteClosing: '\"'}\n\t\tcolumns = []string{\"a\", \"b\", \"c\"}\n\t)\n\tb.P(\"CREATE TABLE\").\n\t\tTable(&schema.Table{Name: \"users\"}).\n\t\tWrap(func(b *Builder) {\n\t\t\tb.MapComma(columns, func(i int, b *Builder) {\n\t\t\t\tb.Ident(columns[i]).P(\"int\").P(\"NOT NULL\")\n\t\t\t})\n\t\t\tb.Comma().P(\"PRIMARY KEY\").Wrap(func(b *Builder) {\n\t\t\t\tb.MapComma(columns, func(i int, b *Builder) {\n\t\t\t\t\tb.Ident(columns[i])\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\trequire.Equal(t, `CREATE TABLE \"users\" (\"a\" int NOT NULL, \"b\" int NOT NULL, \"c\" int NOT NULL, PRIMARY KEY (\"a\", \"b\", \"c\"))`, b.String())\n\n\t// WrapErr.\n\trequire.EqualError(t, b.WrapErr(func(*Builder) error { return errors.New(\"oops\") }), \"oops\")\n\trequire.EqualError(t, b.WrapIndentErr(func(*Builder) error { return errors.New(\"oops\") }), \"oops\")\n}\n\nfunc TestBuilder_Qualifier(t *testing.T) {\n\tvar (\n\t\ts = \"other\"\n\t\tb = &Builder{QuoteOpening: '\"', QuoteClosing: '\"', Schema: &s}\n\t)\n\tb.P(\"CREATE TABLE\").Table(schema.NewTable(\"users\"))\n\trequire.Equal(t, `CREATE TABLE \"other\".\"users\"`, b.String())\n\n\t// Bypass table schema.\n\tb.Reset()\n\tb.P(\"CREATE TABLE\").Table(schema.NewTable(\"users\").SetSchema(schema.New(\"test\")))\n\trequire.Equal(t, `CREATE TABLE \"other\".\"users\"`, b.String())\n\n\t// Empty qualifier, means skip.\n\ts = \"\"\n\tb.Reset()\n\tb.P(\"CREATE TABLE\").Table(schema.NewTable(\"users\").SetSchema(schema.New(\"test\")))\n\trequire.Equal(t, `CREATE TABLE \"users\"`, b.String())\n}\n\nfunc TestQuote(t *testing.T) {\n\tvar (\n\t\ts = \"s1\"\n\t\tb = &Builder{QuoteOpening: '[', QuoteClosing: ']', Schema: &s}\n\t)\n\tb.P(\"EXECUTE sp_rename\").\n\t\tP(\"@newname = N'c2'\").Comma().\n\t\tP(\"@objtype = N'COLUMN'\").Comma()\n\tb.P(\"@objname = \").Quote(\"N\", func(b *Builder) {\n\t\tb.TableResource(schema.NewTable(\"t1\"), &schema.Column{Name: \"c1\"})\n\t})\n\trequire.Equal(t, `EXECUTE sp_rename @newname = N'c2', @objtype = N'COLUMN', @objname = N'[s1].[t1].[c1]'`, b.String())\n}\nfunc TestMayWrap(t *testing.T) {\n\ttests := []struct {\n\t\tinput   string\n\t\twrapped bool\n\t}{\n\t\t{\"\", true},\n\t\t{\"()\", false},\n\t\t{\"('text')\", false},\n\t\t{\"('(')\", false},\n\t\t{`('(\\\\')`, false},\n\t\t{`('\\')(')`, false},\n\t\t{`(a) in (b)`, true},\n\t\t{`a in (b)`, true},\n\t\t{`(\"\\\\\\\\(((('\")`, false},\n\t\t{`('(')||(')')`, true},\n\t\t// Test examples from SQLite.\n\t\t{\"b || 'x'\", true},\n\t\t{\"a+1\", true},\n\t\t{\"substr(x, 2)\", true},\n\t\t{\"(json_extract(x, '$.a'))\", false},\n\t\t{\"(substr(a, 2) COLLATE NOCASE)\", false},\n\t\t{\"(b+random())\", false},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\texpect := tt.input\n\t\t\tif tt.wrapped {\n\t\t\t\texpect = \"(\" + expect + \")\"\n\t\t\t}\n\t\t\trequire.Equal(t, expect, MayWrap(tt.input))\n\t\t})\n\t}\n}\n\nfunc TestExprLastIndex(t *testing.T) {\n\ttests := []struct {\n\t\tinput   string\n\t\twantIdx int\n\t}{\n\t\t{\"\", -1},\n\t\t{\"()\", 1},\n\t\t{\"'('\", 2},\n\t\t{\"('(')\", 4},\n\t\t{\"('text')\", 7},\n\t\t{\"floor(x), y\", 7},\n\t\t{\"f(floor(x), y)\", 13},\n\t\t{\"f(floor(x), y, (z))\", 18},\n\t\t{\"f(x, (x*2)), y, (z)\", 10},\n\t\t{\"(a || ' ' || b)\", 14},\n\t\t{\"(a || ', ' || b)\", 15},\n\t\t{\"a || ', ' || b, x\", 13},\n\t\t{\"(a || ', ' || b), x\", 15},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tidx := ExprLastIndex(tt.input)\n\t\t\trequire.Equal(t, tt.wantIdx, idx)\n\t\t})\n\t}\n}\n\nfunc TestIsQuoted(t *testing.T) {\n\ttests := []struct {\n\t\tinput  string\n\t\tquotes []byte\n\t\twant   bool\n\t}{\n\t\t{\"''\", []byte{'\"', '\\''}, true},\n\t\t{`\"\"`, []byte{'\"', '\\''}, true},\n\t\t{\"' '' \\\"\\\"'' '\", []byte{'\\''}, true},\n\t\t{\"''''''''\", []byte{'\\''}, true},\n\t\t{\"'foo'''\", []byte{'\\''}, true},\n\t\t{\"'foo'''''\", []byte{'\\''}, true},\n\t\t{\"'foo'', '''\", []byte{'\\''}, true},\n\t\t{\"'foo bar'\", []byte{'\\''}, true},\n\t\t{`\"never say \\\"never\\\"\"`, []byte{'\"'}, true},\n\t\t{`\"never say \\\"never\\'\"`, []byte{'\"'}, true},\n\t\t{`'never say \\\"never\\''`, []byte{'\\''}, true},\n\n\t\t{\"'\", []byte{'\"', '\\''}, false},\n\t\t{`\"`, []byte{'\"', '\\''}, false},\n\t\t{\"'foo' ''\", []byte{'\\''}, false},\n\t\t{\"'foo' ()  ''\", []byte{'\\''}, false},\n\t\t{\"'foo', ''\", []byte{'\\''}, false},\n\t\t{\"'foo', 'bar'\", []byte{'\\''}, false},\n\t\t{\"'foo',\\\" 'bar'\", []byte{'\\''}, false},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tquoted := IsQuoted(tt.input, tt.quotes...)\n\t\t\trequire.Equal(t, tt.want, quoted)\n\t\t})\n\t}\n}\n\nfunc TestReverseChanges(t *testing.T) {\n\ttests := []struct {\n\t\tinput  []schema.Change\n\t\texpect []schema.Change\n\t}{\n\t\t{\n\t\t\tinput: []schema.Change{\n\t\t\t\t(*schema.AddColumn)(nil),\n\t\t\t},\n\t\t\texpect: []schema.Change{\n\t\t\t\t(*schema.AddColumn)(nil),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: []schema.Change{\n\t\t\t\t(*schema.AddColumn)(nil),\n\t\t\t\t(*schema.DropColumn)(nil),\n\t\t\t},\n\t\t\texpect: []schema.Change{\n\t\t\t\t(*schema.DropColumn)(nil),\n\t\t\t\t(*schema.AddColumn)(nil),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: []schema.Change{\n\t\t\t\t(*schema.AddColumn)(nil),\n\t\t\t\t(*schema.ModifyColumn)(nil),\n\t\t\t\t(*schema.DropColumn)(nil),\n\t\t\t},\n\t\t\texpect: []schema.Change{\n\t\t\t\t(*schema.DropColumn)(nil),\n\t\t\t\t(*schema.ModifyColumn)(nil),\n\t\t\t\t(*schema.AddColumn)(nil),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: []schema.Change{\n\t\t\t\t(*schema.AddColumn)(nil),\n\t\t\t\t(*schema.ModifyColumn)(nil),\n\t\t\t\t(*schema.DropColumn)(nil),\n\t\t\t\t(*schema.ModifyColumn)(nil),\n\t\t\t},\n\t\t\texpect: []schema.Change{\n\t\t\t\t(*schema.ModifyColumn)(nil),\n\t\t\t\t(*schema.DropColumn)(nil),\n\t\t\t\t(*schema.ModifyColumn)(nil),\n\t\t\t\t(*schema.AddColumn)(nil),\n\t\t\t},\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tReverseChanges(tt.input)\n\t\t\trequire.Equal(t, tt.expect, tt.input)\n\t\t})\n\t}\n}\n\nfunc TestIsUint(t *testing.T) {\n\trequire.True(t, IsUint(\"1\"))\n\trequire.False(t, IsUint(\"-1\"))\n\trequire.False(t, IsUint(\"1.2\"))\n\trequire.False(t, IsUint(\"1.2.3\"))\n}\n\nfunc TestBodyDefChanged(t *testing.T) {\n\tfor i, tt := range []struct {\n\t\tfrom, to string\n\t\tchanged  bool\n\t}{\n\t\t{\"\", \"\", false},\n\t\t{\"a\", \"a\", false},\n\t\t{\"a\", \"b\", true},\n\t\t{\"select 1;\", \"select 1\", false},\n\t\t{\"\\nselect 1\\n\", \"\\nselect 1;\", false},\n\t\t{\"\\nselect \\n  \\n1\\n\", \"\\nselect \\n\\n1;\", false},\n\t\t{\"\\nselect \\n  \\n1\\n'  '\", \"\\nselect \\n\\n' ';\", true},\n\t} {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\trequire.Equal(t, tt.changed, BodyDefChanged(tt.from, tt.to))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "sql/migrate/dir.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage migrate\n\nimport (\n\t\"archive/tar\"\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"slices\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"text/template\"\n\t\"time\"\n)\n\ntype (\n\t// Dir wraps the functionality used to interact with a migration directory.\n\tDir interface {\n\t\tfs.FS\n\t\t// WriteFile writes the data to the named file.\n\t\tWriteFile(string, []byte) error\n\n\t\t// Files returns a set of files stored in this Dir to be executed on a database.\n\t\tFiles() ([]File, error)\n\n\t\t// Checksum returns a HashFile of the migration directory.\n\t\tChecksum() (HashFile, error)\n\t}\n\n\t// File represents a single migration file.\n\tFile interface {\n\t\t// Name returns the name of the migration file.\n\t\tName() string\n\t\t// Desc returns the description of the migration File.\n\t\tDesc() string\n\t\t// Version returns the version of the migration File.\n\t\tVersion() string\n\t\t// Bytes returns the read content of the file.\n\t\tBytes() []byte\n\t\t// Stmts returns the set of SQL statements this file holds.\n\t\tStmts() ([]string, error)\n\t\t// StmtDecls returns the set of SQL statements this file holds alongside its preceding comments.\n\t\tStmtDecls() ([]*Stmt, error)\n\t}\n\n\t// Formatter wraps the Format method.\n\tFormatter interface {\n\t\t// Format formats the given Plan into one or more migration files.\n\t\tFormat(*Plan) ([]File, error)\n\t}\n)\n\ntype (\n\t// CheckpointDir wraps the functionality used to interact\n\t// with a migration directory that support checkpoints.\n\tCheckpointDir interface {\n\t\tDir\n\t\t// WriteCheckpoint writes the given checkpoint file to the migration directory.\n\t\tWriteCheckpoint(name, tag string, content []byte) error\n\n\t\t// CheckpointFiles returns a set of checkpoint files stored in this Dir,\n\t\t// ordered by name.\n\t\tCheckpointFiles() ([]File, error)\n\n\t\t// FilesFromCheckpoint returns the files to be executed on a database from\n\t\t// the given checkpoint file, including it. An ErrCheckpointNotFound if the\n\t\t// checkpoint file is not found in the directory.\n\t\tFilesFromCheckpoint(string) ([]File, error)\n\t}\n\n\t// CheckpointFile wraps the functionality used to interact with files\n\t// returned from a CheckpointDir.\n\tCheckpointFile interface {\n\t\tFile\n\t\t// IsCheckpoint returns true if the file is a checkpoint file.\n\t\tIsCheckpoint() bool\n\n\t\t// CheckpointTag returns the tag of the checkpoint file, if defined. The tag\n\t\t// can be derived from the file name, internal metadata or directive comments.\n\t\t//\n\t\t// An ErrNotCheckpoint is returned if the file is not a checkpoint file.\n\t\tCheckpointTag() (string, error)\n\t}\n)\n\nvar (\n\t// ErrNotCheckpoint is returned when calling CheckpointFile methods on a non-checkpoint file.\n\tErrNotCheckpoint = errors.New(\"not a checkpoint file\")\n\t// ErrCheckpointNotFound is returned when a checkpoint file is not found in the directory.\n\tErrCheckpointNotFound = errors.New(\"no checkpoint found\")\n)\n\n// LocalDir implements Dir for a local migration\n// directory with default Atlas formatting.\ntype LocalDir struct {\n\tpath string\n}\n\nvar _ CheckpointDir = (*LocalDir)(nil)\n\n// NewLocalDir returns a new the Dir used by a Planner to work on the given local path.\nfunc NewLocalDir(path string) (*LocalDir, error) {\n\tfi, err := os.Stat(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/migrate: %w\", err)\n\t}\n\tif !fi.IsDir() {\n\t\treturn nil, fmt.Errorf(\"sql/migrate: %q is not a dir\", path)\n\t}\n\treturn &LocalDir{path: path}, nil\n}\n\n// Path returns the local path used for opening this dir.\nfunc (d *LocalDir) Path() string {\n\treturn d.path\n}\n\n// Open implements fs.FS.\nfunc (d *LocalDir) Open(name string) (fs.File, error) {\n\tf, err := os.Open(filepath.Join(d.path, name))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn f, nil\n}\n\n// WriteFile implements Dir.WriteFile.\nfunc (d *LocalDir) WriteFile(name string, b []byte) error {\n\treturn os.WriteFile(filepath.Join(d.path, name), b, 0644)\n}\n\n// Files implements Dir.Files. It looks for all files with .sql suffix and orders them by filename.\nfunc (d *LocalDir) Files() ([]File, error) {\n\tnames, err := fs.Glob(d, \"*.sql\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Sort files lexicographically.\n\tsort.Slice(names, func(i, j int) bool {\n\t\treturn names[i] < names[j]\n\t})\n\tfiles := make([]File, 0, len(names))\n\tfor _, n := range names {\n\t\tb, err := fs.ReadFile(d, n)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sql/migrate: read file %q: %w\", n, err)\n\t\t}\n\t\tfiles = append(files, NewLocalFile(n, b))\n\t}\n\treturn files, nil\n}\n\n// Checksum implements Dir.Checksum. By default, it calls Files() and creates a checksum from them.\nfunc (d *LocalDir) Checksum() (HashFile, error) {\n\tfiles, err := d.Files()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn NewHashFile(files)\n}\n\n// WriteCheckpoint is like WriteFile, but marks the file as a checkpoint file.\nfunc (d *LocalDir) WriteCheckpoint(name, tag string, b []byte) error {\n\tvar (\n\t\targs []string\n\t\tf    = NewLocalFile(name, b)\n\t)\n\tif tag != \"\" {\n\t\targs = append(args, tag)\n\t}\n\tf.AddDirective(directiveCheckpoint, args...)\n\treturn d.WriteFile(name, f.Bytes())\n}\n\n// CheckpointFiles implements CheckpointDir.CheckpointFiles.\nfunc (d *LocalDir) CheckpointFiles() ([]File, error) {\n\treturn checkpointFiles(d)\n}\n\n// FilesFromCheckpoint implements CheckpointDir.FilesFromCheckpoint.\nfunc (d *LocalDir) FilesFromCheckpoint(name string) ([]File, error) {\n\treturn filesFromCheckpoint(d, name)\n}\n\n// LocalFile is used by LocalDir to implement the Scanner interface.\ntype LocalFile struct {\n\tn string\n\tb []byte\n}\n\nvar _ CheckpointFile = (*LocalFile)(nil)\n\n// NewLocalFile returns a new local file.\nfunc NewLocalFile(name string, data []byte) *LocalFile {\n\treturn &LocalFile{n: name, b: data}\n}\n\n// Name implements File.Name.\nfunc (f *LocalFile) Name() string {\n\treturn f.n\n}\n\n// Desc implements File.Desc.\nfunc (f *LocalFile) Desc() string {\n\tparts := strings.SplitN(f.n, \"_\", 2)\n\tif len(parts) == 1 {\n\t\treturn \"\"\n\t}\n\treturn strings.TrimSuffix(parts[1], \".sql\")\n}\n\n// Version implements File.Version.\nfunc (f *LocalFile) Version() string {\n\treturn strings.SplitN(strings.TrimSuffix(f.n, \".sql\"), \"_\", 2)[0]\n}\n\n// Stmts returns the SQL statement exists in the local file.\nfunc (f *LocalFile) Stmts() ([]string, error) {\n\ts, err := Stmts(string(f.b))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tstmts := make([]string, len(s))\n\tfor i := range s {\n\t\tstmts[i] = s[i].Text\n\t}\n\treturn stmts, nil\n}\n\n// StmtDecls returns the all statement declarations exist in the local file.\nfunc (f *LocalFile) StmtDecls() ([]*Stmt, error) {\n\treturn Stmts(string(f.b))\n}\n\n// Bytes returns local file data.\nfunc (f *LocalFile) Bytes() []byte {\n\treturn f.b\n}\n\n// isCheckpoint reports whether the file is a checkpoint file.\nfunc (f *LocalFile) isCheckpoint() bool {\n\treturn len(f.Directive(directiveCheckpoint)) > 0\n}\n\n// checkpointTag returns the tag of the checkpoint file, if defined.\nfunc (f *LocalFile) checkpointTag() (string, error) {\n\tds := f.Directive(directiveCheckpoint)\n\tif len(ds) == 0 {\n\t\treturn \"\", ErrNotCheckpoint\n\t}\n\treturn ds[0], nil\n}\n\nconst (\n\t// atlas:sum directive.\n\tdirectiveSum  = \"sum\"\n\tsumModeIgnore = \"ignore\"\n\t// atlas:delimiter directive.\n\tdirectiveDelimiter = \"delimiter\"\n\t// atlas:checkpoint directive.\n\tdirectiveCheckpoint = \"checkpoint\"\n\tdirectivePrefixSQL  = \"-- \"\n)\n\nvar reDirective = regexp.MustCompile(`^([ -~]*)atlas:(\\w+)(?: +(.+))*`)\n\n// directive searches in the content a line that matches a directive\n// with the given prefix and name. For example:\n//\n//\tdirective(c, \"delimiter\", \"-- \")\t// '-- atlas:delimiter.*'\n//\tdirective(c, \"sum\", \"\")\t\t\t\t// 'atlas:sum.*'\n//\tdirective(c, \"sum\")\t\t\t\t\t// '.*atlas:sum'\nfunc directive(content, name string, prefix ...string) (string, bool) {\n\tm := reDirective.FindStringSubmatch(content)\n\t// In case the prefix was provided ensures it is matched.\n\tif len(m) == 4 && m[2] == name && (len(prefix) == 0 || prefix[0] == m[1]) {\n\t\treturn m[3], true\n\t}\n\treturn \"\", false\n}\n\n// parseDirective returns the directive name and its arguments.\n// Empty strings are returned if the directive is invalid.\nfunc parseDirective(content string) (string, string) {\n\tm := reDirective.FindStringSubmatch(content)\n\tif len(m) != 4 {\n\t\treturn \"\", \"\"\n\t}\n\treturn m[2], m[3]\n}\n\n// Directive returns the (global) file directives that match the provided name.\n// File directives are located at the top of the file and should not be associated with any\n// statement. Hence, double new lines are used to separate file directives from its content.\nfunc (f *LocalFile) Directive(name string) (ds []string) {\n\tfor _, c := range f.comments() {\n\t\tif d, ok := directive(c, name); ok {\n\t\t\tds = append(ds, d)\n\t\t}\n\t}\n\treturn ds\n}\n\n// AddDirective adds a new directive to the file.\nfunc (f *LocalFile) AddDirective(name string, args ...string) {\n\tvar b strings.Builder\n\tb.WriteString(\"-- atlas:\" + name)\n\tif len(args) > 0 {\n\t\tb.WriteByte(' ')\n\t\tb.WriteString(strings.Join(args, \" \"))\n\t}\n\tb.WriteByte('\\n')\n\tif len(f.comments()) == 0 {\n\t\tb.WriteByte('\\n')\n\t}\n\tf.b = append([]byte(b.String()), f.b...)\n}\n\nfunc (f *LocalFile) comments() []string {\n\tvar (\n\t\tcomments []string\n\t\tcontent  = string(f.b)\n\t)\n\tfor strings.HasPrefix(content, \"#\") || strings.HasPrefix(content, \"--\") {\n\t\tidx := strings.IndexByte(content, '\\n')\n\t\tif idx == -1 {\n\t\t\t// Comments-only file.\n\t\t\tcomments = append(comments, content)\n\t\t\tbreak\n\t\t}\n\t\tcomments = append(comments, strings.TrimSpace(content[:idx]))\n\t\tcontent = content[idx+1:]\n\t}\n\t// File comments are separated by double newlines from file content (detached from actual statements).\n\t// However, if the file does not contain any statements (only comments, such as atlas:import) then the\n\t// collected comments should treat as file comments.\n\tif !strings.HasPrefix(strings.TrimLeft(content, \" \\t\"), \"\\n\") && content != \"\" {\n\t\treturn nil\n\t}\n\treturn comments\n}\n\ntype (\n\t// MemDir provides an in-memory Dir implementation.\n\tMemDir struct {\n\t\tfs     map[string]*LocalFile\n\t\tsyncTo []func(string, []byte) error\n\t\t// Optional path for the MemDir set by its creator.\n\t\t// See SetPath() and Path() methods.\n\t\tpath string\n\t}\n\t// An opened MemDir.\n\topenedMem struct {\n\t\tdir    *MemDir\n\t\tnumUse int\n\t}\n)\n\nvar (\n\t// A list of the opened memory-based directories.\n\tmemDirs struct {\n\t\tsync.Mutex\n\t\topened map[string]*openedMem\n\t}\n\t_ CheckpointDir = (*MemDir)(nil)\n)\n\n// OpenMemDir opens an in-memory directory and registers it in the process namespace\n// with the given name. Hence, calling OpenMemDir with the same name will return the\n// same directory. The directory is deleted when the last reference of it is closed.\nfunc OpenMemDir(name string) *MemDir {\n\tmemDirs.Lock()\n\tdefer memDirs.Unlock()\n\tif m, ok := memDirs.opened[name]; ok {\n\t\tm.numUse++\n\t\treturn m.dir\n\t}\n\tif memDirs.opened == nil {\n\t\tmemDirs.opened = make(map[string]*openedMem)\n\t}\n\tmemDirs.opened[name] = &openedMem{dir: &MemDir{}, numUse: 1}\n\treturn memDirs.opened[name].dir\n}\n\n// Open implements fs.FS.\nfunc (d *MemDir) Open(name string) (fs.File, error) {\n\tf, ok := d.fs[name]\n\tif !ok {\n\t\treturn nil, fs.ErrNotExist\n\t}\n\treturn &memFile{\n\t\tReadCloser: io.NopCloser(bytes.NewReader(f.Bytes())),\n\t}, nil\n}\n\n// Reset the in-memory directory to its initial state.\nfunc (d *MemDir) Reset() {\n\td.fs = nil\n\td.syncTo = nil\n}\n\n// Close implements the io.Closer interface.\nfunc (d *MemDir) Close() error {\n\tmemDirs.Lock()\n\tdefer memDirs.Unlock()\n\tvar opened string\n\tfor name, m := range memDirs.opened {\n\t\tswitch {\n\t\tcase m.dir != d:\n\t\tcase opened != \"\":\n\t\t\treturn fmt.Errorf(\"dir was opened with different names: %q and %q\", opened, name)\n\t\tdefault:\n\t\t\topened = name\n\t\t\tif m.numUse--; m.numUse == 0 {\n\t\t\t\tdelete(memDirs.opened, name)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// WriteFile adds a new file in-memory.\nfunc (d *MemDir) WriteFile(name string, data []byte) error {\n\tif d.fs == nil {\n\t\td.fs = make(map[string]*LocalFile)\n\t}\n\td.fs[name] = NewLocalFile(name, data)\n\tfor _, f := range d.syncTo {\n\t\tif err := f(name, data); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// CopyFiles copies all files to the MemDir and update the\n// atlas.sum file, or create it if it does not exist.\nfunc (d *MemDir) CopyFiles(fs []File) error {\n\tfor _, f := range fs {\n\t\tif err := d.WriteFile(f.Name(), f.Bytes()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tsum, err := NewHashFile(fs)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn WriteSumFile(d, sum)\n}\n\n// WriteCheckpoint is like WriteFile, but marks the file as a checkpoint file.\nfunc (d *MemDir) WriteCheckpoint(name, tag string, b []byte) error {\n\tvar (\n\t\targs []string\n\t\tf    = NewLocalFile(name, b)\n\t)\n\tif tag != \"\" {\n\t\targs = append(args, tag)\n\t}\n\tf.AddDirective(directiveCheckpoint, args...)\n\treturn d.WriteFile(name, f.Bytes())\n}\n\n// CheckpointFiles implements CheckpointDir.CheckpointFiles.\nfunc (d *MemDir) CheckpointFiles() ([]File, error) {\n\treturn checkpointFiles(d)\n}\n\n// FilesFromCheckpoint implements CheckpointDir.FilesFromCheckpoint.\nfunc (d *MemDir) FilesFromCheckpoint(name string) ([]File, error) {\n\treturn filesFromCheckpoint(d, name)\n}\n\n// SyncWrites allows syncing writes from in-memory directory\n// the underlying storage.\nfunc (d *MemDir) SyncWrites(fs ...func(string, []byte) error) {\n\td.syncTo = append(d.syncTo, fs...)\n}\n\n// Files returns a set of files stored in-memory to be executed on a database.\nfunc (d *MemDir) Files() ([]File, error) {\n\tfiles := make([]File, 0, len(d.fs))\n\tfor _, f := range d.fs {\n\t\tif filepath.Ext(f.Name()) == \".sql\" {\n\t\t\tfiles = append(files, f)\n\t\t}\n\t}\n\tsort.Slice(files, func(i, j int) bool {\n\t\treturn files[i].Name() < files[j].Name()\n\t})\n\treturn files, nil\n}\n\n// Checksum implements Dir.Checksum.\nfunc (d *MemDir) Checksum() (HashFile, error) {\n\tfiles, err := d.Files()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn NewHashFile(files)\n}\n\n// SetPath allows the caller to set a path that can be retrieved by a user using the Path method.\n// Although MemDir resides only in memory, its source can be associated with a real directory\n// (such as a template directory).\nfunc (d *MemDir) SetPath(path string) {\n\td.path = path\n}\n\n// Path returns the path set by the SetPath method.\nfunc (d *MemDir) Path() string {\n\treturn d.path\n}\n\nconst versionFormat = \"20060102150405\"\n\n// NewVersion generates a new migration version.\nfunc NewVersion() string {\n\treturn time.Now().UTC().Format(versionFormat)\n}\n\n// CheckVersion checks if the given version is valid Atlas version.\nfunc CheckVersion(v string) error {\n\tif _, err := time.Parse(versionFormat, v); err != nil {\n\t\treturn fmt.Errorf(\"invalid version: %w. Expected format is: %s\", err, versionFormat)\n\t}\n\treturn nil\n}\n\n// delim formats the given string as an atlas:delimiter directive.\nfunc delim(s string) string {\n\t// Escape delimiters. e.g. \"\\n\" => \"\\\\n\".\n\ts = strings.NewReplacer(\"\\n\", `\\n`, \"\\r\", `\\r`, \"\\t\", `\\t`).Replace(s)\n\treturn fmt.Sprintf(\"-- atlas:%s %s\", directiveDelimiter, s)\n}\n\n// directives returns the all directives of the plan, if exists.\nfunc directives(p *Plan) (string, error) {\n\tvar ds []string\n\tif p.Delimiter != \"\" {\n\t\tds = append(ds, delim(p.Delimiter))\n\t}\n\tfor _, d := range p.Directives {\n\t\tswitch name, _ := parseDirective(d); {\n\t\tcase name == \"\":\n\t\t\treturn \"\", fmt.Errorf(\"invalid directive: %q\", d)\n\t\tcase name == directiveDelimiter && p.Delimiter != \"\":\n\t\t\treturn \"\", fmt.Errorf(\"duplicate directive: %q. delimiter already set\", d)\n\t\t}\n\t\tds = append(ds, d)\n\t}\n\tif len(ds) == 0 {\n\t\treturn \"\", nil\n\t}\n\treturn fmt.Sprintf(\"%s\\n\\n\", strings.Join(ds, \"\\n\")), nil\n}\n\nvar (\n\t// templateFunc contains the template.FuncMap for the DefaultFormatter.\n\ttemplateFuncs = template.FuncMap{\n\t\t\"upper\":      strings.ToUpper,\n\t\t\"now\":        NewVersion,\n\t\t\"directives\": directives,\n\t}\n\t// DefaultFormatter is a default implementation for Formatter.\n\tDefaultFormatter = TemplateFormatter{\n\t\t{\n\t\t\tN: template.Must(template.New(\"\").Funcs(templateFuncs).Parse(\n\t\t\t\t\"{{ with .Version }}{{ . }}{{ else }}{{ now }}{{ end }}{{ with .Name }}_{{ . }}{{ end }}.sql\",\n\t\t\t)),\n\t\t\tC: template.Must(template.New(\"\").Funcs(templateFuncs).Parse(\n\t\t\t\t`{{ directives . }}{{ range .Changes }}{{ with .Comment }}{{ printf \"-- %s%s\\n\" (slice . 0 1 | upper ) (slice . 1) }}{{ end }}{{ printf \"%s%s\\n\" .Cmd (or $.Delimiter \";\") }}{{ end }}`,\n\t\t\t)),\n\t\t},\n\t}\n)\n\n// TemplateFormatter implements Formatter by using templates.\ntype TemplateFormatter []struct{ N, C *template.Template }\n\n// NewTemplateFormatter creates a new Formatter working with the given templates.\n//\n//\tmigrate.NewTemplateFormatter(\n//\t\ttemplate.Must(template.New(\"\").Parse(\"{{now.Unix}}{{.Name}}.sql\")),                 // name template\n//\t\ttemplate.Must(template.New(\"\").Parse(\"{{range .Changes}}{{println .Cmd}}{{end}}\")), // content template\n//\t)\nfunc NewTemplateFormatter(templates ...*template.Template) (TemplateFormatter, error) {\n\tif n := len(templates); n == 0 || n%2 == 1 {\n\t\treturn nil, fmt.Errorf(\"zero or odd number of templates given: %d\", n)\n\t}\n\tt := make(TemplateFormatter, 0, len(templates))\n\tfor i := 0; i < len(templates); i += 2 {\n\t\tt = append(t, struct{ N, C *template.Template }{templates[i], templates[i+1]})\n\t}\n\treturn t, nil\n}\n\n// Format implements the Formatter interface.\nfunc (t TemplateFormatter) Format(plan *Plan) ([]File, error) {\n\tfiles := make([]File, 0, len(t))\n\tfor _, tpl := range t {\n\t\tvar n, b bytes.Buffer\n\t\tif err := tpl.N.Execute(&n, plan); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := tpl.C.Execute(&b, plan); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfiles = append(files, &LocalFile{\n\t\t\tn: n.String(),\n\t\t\tb: b.Bytes(),\n\t\t})\n\t}\n\treturn files, nil\n}\n\n// FormatFile is like Format, but expects and returns a single file.\nfunc (t TemplateFormatter) FormatFile(p *Plan) (File, error) {\n\tfiles, err := t.Format(p)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(files) != 1 {\n\t\treturn nil, fmt.Errorf(\"expected a single file, got %d\", len(files))\n\t}\n\treturn files[0], nil\n}\n\n// FormatTo calls Format and writes the files' content to the given writer.\nfunc (t TemplateFormatter) FormatTo(plan *Plan, w io.Writer) error {\n\tfiles, err := t.Format(plan)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, f := range files {\n\t\tif _, err := w.Write(f.Bytes()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// HashFileName of the migration directory integrity sum file.\nconst HashFileName = \"atlas.sum\"\n\n// HashFile represents the integrity sum file of the migration dir.\ntype HashFile []struct{ N, H string }\n\n// NewHashFile computes and returns a HashFile from the given directory's files.\nfunc NewHashFile(files []File) (HashFile, error) {\n\tvar (\n\t\ths HashFile\n\t\th  = sha256.New()\n\t)\n\tfor _, f := range files {\n\t\tif _, err := h.Write([]byte(f.Name())); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// Check if this file contains an \"atlas:sum\" directive and if so, act to it.\n\t\tif mode, ok := directive(string(f.Bytes()), directiveSum); ok && mode == sumModeIgnore {\n\t\t\tcontinue\n\t\t}\n\t\tif _, err := h.Write(f.Bytes()); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ths = append(hs, struct{ N, H string }{f.Name(), base64.StdEncoding.EncodeToString(h.Sum(nil))})\n\t}\n\treturn hs, nil\n}\n\n// WriteSumFile writes the given HashFile to the Dir. If the file does not exist, it is created.\nfunc WriteSumFile(dir Dir, sum HashFile) error {\n\tb, err := sum.MarshalText()\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn dir.WriteFile(HashFileName, b)\n}\n\n// Sum returns the checksum of the represented hash file.\nfunc (f HashFile) Sum() string {\n\tsha := sha256.New()\n\tfor _, f := range f {\n\t\tsha.Write([]byte(f.N))\n\t\tsha.Write([]byte(f.H))\n\t}\n\treturn base64.StdEncoding.EncodeToString(sha.Sum(nil))\n}\n\n// MarshalText implements encoding.TextMarshaler.\nfunc (f HashFile) MarshalText() ([]byte, error) {\n\tbuf := new(bytes.Buffer)\n\tfor _, f := range f {\n\t\tfmt.Fprintf(buf, \"%s h1:%s\\n\", f.N, f.H)\n\t}\n\treturn []byte(fmt.Sprintf(\"h1:%s\\n%s\", f.Sum(), buf)), nil\n}\n\n// UnmarshalText implements encoding.TextUnmarshaler.\nfunc (f *HashFile) UnmarshalText(b []byte) error {\n\tsc := bufio.NewScanner(bytes.NewReader(b))\n\t// The first line contains the sum.\n\tsc.Scan()\n\tsum := strings.TrimPrefix(sc.Text(), \"h1:\")\n\tfor sc.Scan() {\n\t\tli := strings.SplitN(sc.Text(), \"h1:\", 2)\n\t\tif len(li) != 2 {\n\t\t\treturn ErrChecksumFormat\n\t\t}\n\t\t*f = append(*f, struct{ N, H string }{strings.TrimSpace(li[0]), li[1]})\n\t}\n\tif sum != f.Sum() {\n\t\treturn ErrChecksumMismatch\n\t}\n\treturn sc.Err()\n}\n\n// SumByName returns the hash for a migration file by its name.\nfunc (f HashFile) SumByName(n string) (string, error) {\n\tfor _, f := range f {\n\t\tif f.N == n {\n\t\t\treturn f.H, nil\n\t\t}\n\t}\n\treturn \"\", errors.New(\"checksum not found\")\n}\n\n// Reason for a checksum mismatch.\nconst (\n\tReasonAdded Reason = iota + 1\n\tReasonEdited\n\tReasonRemoved\n)\n\nvar (\n\t// ErrChecksumFormat is returned from Validate if the sum files format is invalid.\n\tErrChecksumFormat = errors.New(\"checksum file format invalid\")\n\t// ErrChecksumMismatch is returned when unmarshalling from a sum file and the files sum entries don't match.\n\tErrChecksumMismatch = errors.New(\"checksum mismatch\")\n\t// ErrChecksumNotFound is returned from Validate if the hash file does not exist.\n\tErrChecksumNotFound = errors.New(\"checksum file not found\")\n)\n\ntype (\n\t// ChecksumError indicates a mismatch between a directories files and its sum.\n\tChecksumError struct {\n\t\tLine, Total, Pos int    // line number in file of the mismatch, total number of lines, pos in file\n\t\tFile             string // filename of the mismatch\n\t\tReason           Reason // reason of a mismatch by filename\n\t}\n\t// Reason for a checksum mismatch.\n\tReason uint\n)\n\n// Error implements the error interface.\nfunc (err *ChecksumError) Error() string { return ErrChecksumMismatch.Error() }\n\n// Is exists for backwards compatability reasons.\nfunc (err *ChecksumError) Is(target error) bool {\n\treturn errors.Is(ErrChecksumMismatch, target)\n}\n\n// String implements fmt.Stringer.\nfunc (r Reason) String() string {\n\tswitch r {\n\tcase ReasonAdded:\n\t\treturn \"added\"\n\tcase ReasonEdited:\n\t\treturn \"edited\"\n\tcase ReasonRemoved:\n\t\treturn \"removed\"\n\t}\n\treturn \"unknown reason\"\n}\n\n// Validate checks if the migration dir is in sync with its sum file.\n// If they don't match ErrChecksumMismatch is returned.\nfunc Validate(dir Dir) error {\n\tac, err := readHashFile(dir)\n\tif errors.Is(err, fs.ErrNotExist) {\n\t\t// If there are no migration files yet, this is okay.\n\t\tif files, err := dir.Files(); err != nil {\n\t\t\treturn err\n\t\t} else if len(files) > 0 {\n\t\t\treturn ErrChecksumNotFound\n\t\t}\n\t\treturn nil\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\tex, err := dir.Checksum()\n\tif err != nil {\n\t\treturn err\n\t}\n\tif ac.Sum() != ex.Sum() {\n\t\terr := &ChecksumError{Total: len(ac)}\n\t\t// Determine the reason for the mismatch. Iterate over the file sum,\n\t\t// based on it determine if a file was removed, added or edited.\n\t\tconst hashSize = 3 + 44 // h1: (3) + base64(sha256sum) (44)\n\t\tpos := hashSize + 1     // total hash + newline\n\t\tfor i, h := range ac {\n\t\t\t// Proceed until we find the mismatch.\n\t\t\tif len(ex) > i && ex[i] == h {\n\t\t\t\tpos += len(h.N) + 1 + hashSize + 1 // filename + space + hash + newline\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Index is now pointing at the file with the mismatch.\n\t\t\terr.Line = i + 2 // first line is global hash\n\t\t\terr.Pos = pos\n\t\t\terr.File = h.N\n\t\t\tswitch idx := slices.IndexFunc(ex, func(e struct{ N, H string }) bool { return e.N == h.N }); {\n\t\t\tcase idx < 0:\n\t\t\t\terr.Reason = ReasonRemoved\n\t\t\tcase idx == i:\n\t\t\t\t// If the file is in its original place, it was edited.\n\t\t\t\terr.Reason = ReasonEdited\n\t\t\tdefault:\n\t\t\t\t// File was not in its original place, meaning another file was added before it.\n\t\t\t\terr.File = ex[i].N\n\t\t\t\terr.Reason = ReasonAdded\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\t// If we land here, all migrations in the sum file are present unchanged in the computed sum.\n\t\t// But there is a mismatch, meaning the next file in the computed sum was added.\n\t\terr.Line = err.Total + 2 // first line is global hash\n\t\terr.File = ex[err.Total].N\n\t\terr.Pos = pos\n\t\terr.Reason = ReasonAdded\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// FilesLastIndex returns the index of the last file\n// satisfying f(i), or -1 if none do.\nfunc FilesLastIndex[F File](files []F, f func(F) bool) int {\n\tfor i := len(files) - 1; i >= 0; i-- {\n\t\tif f(files[i]) {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// SkipCheckpointFiles returns a filtered set of files that are not checkpoint files.\nfunc SkipCheckpointFiles(all []File) []File {\n\tfiles := make([]File, 0, len(all))\n\tfor _, f := range all {\n\t\tif ck, ok := f.(CheckpointFile); ok && ck.IsCheckpoint() {\n\t\t\tcontinue\n\t\t}\n\t\tfiles = append(files, f)\n\t}\n\treturn files\n}\n\n// FilesFromLastCheckpoint returns a set of files created after the last checkpoint,\n// if exists, to be executed on a database (on the first time). Note, if the Dir is\n// not a CheckpointDir, or no checkpoint file was found, all files are returned.\nfunc FilesFromLastCheckpoint(dir Dir) ([]File, error) {\n\tck, ok := dir.(CheckpointDir)\n\tif !ok {\n\t\treturn dir.Files()\n\t}\n\tcks, err := ck.CheckpointFiles()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(cks) == 0 {\n\t\treturn dir.Files()\n\t}\n\treturn ck.FilesFromCheckpoint(cks[len(cks)-1].Name())\n}\n\n// checkpointFiles returns all checkpoint files in a migration directory.\nfunc checkpointFiles(d Dir) ([]File, error) {\n\tfiles, err := d.Files()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar cks []File\n\tfor _, f := range files {\n\t\tif ck, ok := f.(CheckpointFile); ok && ck.IsCheckpoint() {\n\t\t\tcks = append(cks, f)\n\t\t}\n\t}\n\treturn cks, nil\n}\n\n// filesFromCheckpoint returns all files from the given checkpoint\n// to be executed on the database, including the checkpoint file.\nfunc filesFromCheckpoint(d Dir, name string) ([]File, error) {\n\tfiles, err := d.Files()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ti := FilesLastIndex(files, func(f File) bool {\n\t\tc, ok := f.(CheckpointFile)\n\t\treturn ok && c.IsCheckpoint() && f.Name() == name\n\t})\n\tif i == -1 {\n\t\treturn nil, ErrCheckpointNotFound\n\t}\n\treturn files[i:], nil\n}\n\n// readHashFile reads the HashFile from the given Dir.\nfunc readHashFile(dir Dir) (HashFile, error) {\n\tf, err := dir.Open(HashFileName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\tb, err := io.ReadAll(f)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar fh HashFile\n\tif err := fh.UnmarshalText(b); err != nil {\n\t\treturn nil, err\n\t}\n\treturn fh, nil\n}\n\n// memFile implements the File interface for a file in memory.\ntype memFile struct{ io.ReadCloser }\n\n// Stat returns a zero FileInfo.\nfunc (m *memFile) Stat() (fs.FileInfo, error) { return m, nil }\nfunc (m *memFile) Name() string               { return \"\" }\nfunc (m *memFile) Size() int64                { return 0 }\nfunc (m *memFile) Mode() fs.FileMode          { return 0 }\nfunc (m *memFile) ModTime() time.Time         { return time.Time{} }\nfunc (m *memFile) IsDir() bool                { return false }\nfunc (m *memFile) Sys() interface{}           { return nil }\n\n// ArchiveDir returns a tar archive of the given directory.\nfunc ArchiveDir(dir Dir) ([]byte, error) {\n\tvar buf bytes.Buffer\n\tif err := ArchiveDirTo(&buf, dir); err != nil {\n\t\treturn nil, err\n\t}\n\treturn buf.Bytes(), nil\n}\n\n// ArchiveDirTo writes a tar archive of the given directory to the given writer.\nfunc ArchiveDirTo(w io.Writer, dir Dir) error {\n\ttw := tar.NewWriter(w)\n\tdefer tw.Close()\n\tsumF, err := dir.Open(HashFileName)\n\tif err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\treturn err\n\t}\n\tif sumF != nil {\n\t\tsumB, err := io.ReadAll(sumF)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := append2Tar(tw, HashFileName, sumB); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfiles, err := dir.Files()\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, f := range files {\n\t\tif err := append2Tar(tw, f.Name(), f.Bytes()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// UnarchiveDir extracts the tar archive into the given directory.\nfunc UnarchiveDir(arc []byte) (Dir, error) {\n\treturn UnarchiveDirFrom(bytes.NewReader(arc))\n}\n\n// UnarchiveDirFrom extracts the tar archive into the given directory.\nfunc UnarchiveDirFrom(r io.Reader) (Dir, error) {\n\tvar (\n\t\tmd = &MemDir{}\n\t\ttr = tar.NewReader(r)\n\t)\n\tfor {\n\t\th, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdata, err := io.ReadAll(tr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := md.WriteFile(h.Name, data); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn md, nil\n}\n\nfunc append2Tar(tw *tar.Writer, name string, data []byte) error {\n\tif err := tw.WriteHeader(&tar.Header{\n\t\tName: name,\n\t\tMode: 0600,\n\t\tSize: int64(len(data)),\n\t}); err != nil {\n\t\treturn err\n\t}\n\tif _, err := tw.Write(data); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "sql/migrate/dir_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage migrate_test\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"compress/gzip\"\n\t_ \"embed\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/sqltool\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestHashSum(t *testing.T) {\n\t// Sum file gets created.\n\tp := t.TempDir()\n\td, err := migrate.NewLocalDir(p)\n\trequire.NoError(t, err)\n\tv := time.Now().UTC().Format(\"20060102150405\")\n\tplan := &migrate.Plan{Version: v, Name: \"plan\", Changes: []*migrate.Change{{Cmd: \"cmd\"}}}\n\tpl := migrate.NewPlanner(nil, d)\n\trequire.NotNil(t, pl)\n\trequire.NoError(t, pl.WritePlan(plan))\n\trequire.Equal(t, 2, countFiles(t, d))\n\trequireFileEqual(t, d, v+\"_plan.sql\", \"cmd;\\n\")\n\trequire.FileExists(t, filepath.Join(p, \"atlas.sum\"))\n\n\t// Disable sum.\n\tp = t.TempDir()\n\td, err = migrate.NewLocalDir(p)\n\trequire.NoError(t, err)\n\tpl = migrate.NewPlanner(nil, d, migrate.PlanWithChecksum(false))\n\trequire.NotNil(t, pl)\n\trequire.NoError(t, pl.WritePlan(plan))\n\trequire.Equal(t, 1, countFiles(t, d))\n\trequireFileEqual(t, d, v+\"_plan.sql\", \"cmd;\\n\")\n\n\t// Files not ending with .sql get ignored.\n\tp = t.TempDir()\n\td, err = migrate.NewLocalDir(p)\n\trequire.NoError(t, err)\n\tpl = migrate.NewPlanner(nil, d)\n\trequire.NotNil(t, pl)\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"include.sql\"), nil, 0600))\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"exclude.txt\"), nil, 0600))\n\trequire.NoError(t, pl.WritePlan(plan))\n\trequire.Equal(t, 4, countFiles(t, d))\n\tc, err := os.ReadFile(filepath.Join(p, \"atlas.sum\"))\n\trequire.NoError(t, err)\n\trequire.Contains(t, string(c), \"include.sql\")\n\trequire.NotContains(t, string(c), \"exclude.txt\")\n\n\t// Files with directive in first line get ignored.\n\tp = t.TempDir()\n\td, err = migrate.NewLocalDir(p)\n\trequire.NoError(t, err)\n\tpl = migrate.NewPlanner(nil, d)\n\trequire.NotNil(t, pl)\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"include.sql\"), []byte(\"//atlas:sum\\nfoo\"), 0600))\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"exclude_1.sql\"), []byte(\"//atlas:sum ignore\\nbar\"), 0600))\n\trequire.NoError(t, os.WriteFile(filepath.Join(p, \"exclude_2.sql\"), []byte(\"atlas:sum ignore\"), 0600))\n\trequire.NoError(t, pl.WritePlan(plan))\n\trequire.Equal(t, 5, countFiles(t, d))\n\trequireFileEqual(t, d, v+\"_plan.sql\", \"cmd;\\n\")\n\tc, err = os.ReadFile(filepath.Join(p, \"atlas.sum\"))\n\trequire.NoError(t, err)\n\trequire.Contains(t, string(c), \"include\")\n\trequire.NotContains(t, string(c), \"exclude_1.sql\")\n\trequire.NotContains(t, string(c), \"exclude_2.sql\")\n}\n\nvar (\n\t//go:embed testdata/migrate/atlas.sum\n\thash []byte\n\t//go:embed testdata/migrate/1_initial.up.sql\n\tinitialUp []byte\n)\n\nfunc TestValidate(t *testing.T) {\n\t// Add the sum file form the testdata/migrate dir without any files in it - should fail.\n\tp := t.TempDir()\n\td, err := migrate.NewLocalDir(p)\n\trequire.NoError(t, err)\n\trequire.NoError(t, d.WriteFile(\"atlas.sum\", hash))\n\trequire.Equal(t, removed(2, 2, 48, \"1_initial.down.sql\"), migrate.Validate(d))\n\n\ttd := \"testdata/migrate\"\n\td, err = migrate.NewLocalDir(td)\n\trequire.NoError(t, err)\n\n\t// testdata/migrate is valid.\n\trequire.Nil(t, migrate.Validate(d))\n\n\t// Making a manual change to the sum file should raise validation error.\n\tf, err := os.OpenFile(filepath.Join(td, \"atlas.sum\"), os.O_RDWR, os.ModeAppend)\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(\"foo\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, f.Close())\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, os.WriteFile(filepath.Join(td, \"atlas.sum\"), hash, 0644))\n\t})\n\trequire.Equal(t, migrate.ErrChecksumMismatch, migrate.Validate(d))\n\trequire.NoError(t, os.WriteFile(filepath.Join(td, \"atlas.sum\"), hash, 0644))\n\tf, err = os.OpenFile(filepath.Join(td, \"atlas.sum\"), os.O_APPEND|os.O_WRONLY, os.ModeAppend)\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(\"foo\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, f.Close())\n\trequire.Equal(t, migrate.ErrChecksumFormat, migrate.Validate(d))\n\trequire.NoError(t, os.WriteFile(filepath.Join(td, \"atlas.sum\"), hash, 0644))\n\n\t// Changing the contents of the file will report it edited.\n\tf, err = os.OpenFile(filepath.Join(td, \"1_initial.up.sql\"), os.O_RDWR, os.ModeAppend)\n\trequire.NoError(t, err)\n\t_, err = f.WriteString(\"something\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, f.Close())\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, os.WriteFile(filepath.Join(td, \"1_initial.up.sql\"), initialUp, 0644))\n\t})\n\trequire.Equal(t, edited(3, 2, 115, \"1_initial.up.sql\"), migrate.Validate(d))\n\trequire.NoError(t, os.WriteFile(filepath.Join(td, \"1_initial.up.sql\"), initialUp, 0644))\n\n\t// Adding a file at the end.\n\trequire.NoError(t, os.WriteFile(filepath.Join(td, \"2_second.sql\"), []byte(\"stmt\"), os.ModePerm))\n\tt.Cleanup(func() { os.Remove(filepath.Join(td, \"2_second.sql\")) })\n\trequire.Equal(t, added(4, 2, 180, \"2_second.sql\"), migrate.Validate(d))\n\trequire.NoError(t, os.Remove(filepath.Join(td, \"2_second.sql\")))\n\n\t// Changing the filename should raise validation error.\n\trequire.NoError(t, os.Rename(filepath.Join(td, \"1_initial.up.sql\"), filepath.Join(td, \"1_first.up.sql\")))\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, os.Rename(filepath.Join(td, \"1_first.up.sql\"), filepath.Join(td, \"1_initial.up.sql\")))\n\t})\n\trequire.Equal(t, added(2, 2, 48, \"1_first.up.sql\"), migrate.Validate(d))\n\n\t// Removing it as well (move it out of the dir).\n\trequire.NoError(t, os.Rename(filepath.Join(td, \"1_first.up.sql\"), filepath.Join(td, \"..\", \"bak\")))\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, os.Rename(filepath.Join(td, \"..\", \"bak\"), filepath.Join(td, \"1_first.up.sql\")))\n\t})\n\trequire.Equal(t, removed(3, 2, 115, \"1_initial.up.sql\"), migrate.Validate(d))\n}\n\nfunc TestHash_MarshalText(t *testing.T) {\n\td, err := migrate.NewLocalDir(\"testdata/migrate\")\n\trequire.NoError(t, err)\n\th, err := d.Checksum()\n\trequire.NoError(t, err)\n\tac, err := h.MarshalText()\n\trequire.Equal(t, hash, ac)\n}\n\nfunc TestHash_UnmarshalText(t *testing.T) {\n\td, err := migrate.NewLocalDir(\"testdata/migrate\")\n\trequire.NoError(t, err)\n\th, err := d.Checksum()\n\trequire.NoError(t, err)\n\tvar ac migrate.HashFile\n\trequire.NoError(t, ac.UnmarshalText(hash))\n\trequire.Equal(t, h, ac)\n}\n\nfunc TestLocalDir(t *testing.T) {\n\t// Files don't work.\n\td, err := migrate.NewLocalDir(\"migrate.go\")\n\trequire.ErrorContains(t, err, \"sql/migrate: \\\"migrate.go\\\" is not a dir\")\n\trequire.Nil(t, d)\n\n\t// Does not create a dir for you.\n\td, err = migrate.NewLocalDir(\"foo/bar\")\n\trequire.EqualError(t, err, \"sql/migrate: stat foo/bar: no such file or directory\")\n\trequire.Nil(t, d)\n\n\t// Open and WriteFile work.\n\td, err = migrate.NewLocalDir(t.TempDir())\n\trequire.NoError(t, err)\n\trequire.NotNil(t, d)\n\trequire.NoError(t, d.WriteFile(\"name\", []byte(\"content\")))\n\tf, err := d.Open(\"name\")\n\trequire.NoError(t, err)\n\ti, err := f.Stat()\n\trequire.NoError(t, err)\n\trequire.Equal(t, i.Name(), \"name\")\n\tc, err := io.ReadAll(f)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"content\", string(c))\n\n\t// Default Dir implementation.\n\td, err = migrate.NewLocalDir(\"testdata/migrate/sub\")\n\trequire.NoError(t, err)\n\trequire.NotNil(t, d)\n\n\tfiles, err := d.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 3)\n\trequire.Equal(t, \"1.a_sub.up.sql\", files[0].Name())\n\trequire.Equal(t, \"2.10.x-20_description.sql\", files[1].Name())\n\trequire.Equal(t, \"3_partly.sql\", files[2].Name())\n\n\tstmts, err := files[0].Stmts()\n\trequire.NoError(t, err)\n\trequire.Equal(t, []string{\"CREATE TABLE t_sub(c int);\", \"ALTER TABLE t_sub ADD c1 int;\"}, stmts)\n\trequire.Equal(t, \"1.a\", files[0].Version())\n\trequire.Equal(t, \"sub.up\", files[0].Desc())\n\n\tstmts, err = files[1].Stmts()\n\trequire.NoError(t, err)\n\trequire.Equal(t, []string{\"ALTER TABLE t_sub ADD c2 int;\"}, stmts)\n\trequire.Equal(t, \"2.10.x-20\", files[1].Version())\n\trequire.Equal(t, \"description\", files[1].Desc())\n}\n\nfunc TestCheckpointDir(t *testing.T) {\n\tlocal, err := migrate.NewLocalDir(t.TempDir())\n\trequire.NoError(t, err)\n\tfor _, d := range []migrate.CheckpointDir{&migrate.MemDir{}, local} {\n\t\tfiles, err := d.Files()\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, files)\n\t\tcks, err := d.CheckpointFiles()\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, cks)\n\t\trequire.NoError(t, migrate.Validate(d))\n\n\t\trequire.NoError(t, d.WriteFile(\"1.sql\", []byte(\"create table t1(c int);\")))\n\t\tsum, err := d.Checksum()\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, migrate.WriteSumFile(d, sum))\n\t\trequire.NoError(t, migrate.Validate(d))\n\t\tfiles, err = d.Files()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 1)\n\t\tcks, err = d.CheckpointFiles()\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, cks)\n\n\t\trequire.NoError(t, d.WriteCheckpoint(\"2_checkpoint.sql\", \"\", []byte(\"create table t1(c int);\")))\n\t\tsum, err = d.Checksum()\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, migrate.WriteSumFile(d, sum))\n\t\trequire.NoError(t, migrate.Validate(d))\n\t\tfiles, err = d.Files()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 2)\n\t\trequire.Equal(t, []string{\"1.sql\", \"2_checkpoint.sql\"}, []string{files[0].Name(), files[1].Name()})\n\t\tfiles = migrate.SkipCheckpointFiles(files)\n\t\trequire.Len(t, files, 1)\n\t\trequire.Equal(t, \"1.sql\", files[0].Name())\n\t\tcks, err = d.CheckpointFiles()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, cks, 1)\n\t\trequire.Equal(t, \"2_checkpoint.sql\", cks[0].Name())\n\n\t\trequire.NoError(t, d.WriteFile(\"3.sql\", []byte(\"create table t2(c int);\")))\n\t\tsum, err = d.Checksum()\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, migrate.WriteSumFile(d, sum))\n\t\trequire.NoError(t, migrate.Validate(d))\n\t\tfiles, err = d.Files()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 3)\n\t\trequire.Equal(t, []string{\"1.sql\", \"2_checkpoint.sql\", \"3.sql\"}, []string{files[0].Name(), files[1].Name(), files[2].Name()})\n\t\tfiles = migrate.SkipCheckpointFiles(files)\n\t\trequire.Len(t, files, 2)\n\t\trequire.Equal(t, []string{\"1.sql\", \"3.sql\"}, []string{files[0].Name(), files[1].Name()})\n\t\tcks, err = d.CheckpointFiles()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, cks, 1)\n\t\trequire.Equal(t, \"2_checkpoint.sql\", cks[0].Name())\n\n\t\trequire.NoError(t, d.WriteCheckpoint(\"4_checkpoint.sql\", \"v4\", []byte(\"create table t1(c int);\\ncreate table t2(c int);\")))\n\t\tsum, err = d.Checksum()\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, migrate.WriteSumFile(d, sum))\n\t\trequire.NoError(t, migrate.Validate(d))\n\t\tfiles, err = d.Files()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 4)\n\t\trequire.Equal(t, []string{\"1.sql\", \"2_checkpoint.sql\", \"3.sql\", \"4_checkpoint.sql\"}, []string{files[0].Name(), files[1].Name(), files[2].Name(), files[3].Name()})\n\t\tfiles = migrate.SkipCheckpointFiles(files)\n\t\trequire.Len(t, files, 2)\n\t\trequire.Equal(t, []string{\"1.sql\", \"3.sql\"}, []string{files[0].Name(), files[1].Name()})\n\t\tcks, err = d.CheckpointFiles()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, cks, 2)\n\t\trequire.Equal(t, []string{\"2_checkpoint.sql\", \"4_checkpoint.sql\"}, []string{cks[0].Name(), cks[1].Name()})\n\t\ttag, err := cks[0].(migrate.CheckpointFile).CheckpointTag()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"\", tag)\n\t\ttag, err = cks[1].(migrate.CheckpointFile).CheckpointTag()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"v4\", tag)\n\t}\n}\n\nfunc TestMemDir(t *testing.T) {\n\tvar d migrate.MemDir\n\tfiles, err := d.Files()\n\trequire.NoError(t, err)\n\trequire.Empty(t, files)\n\trequire.NoError(t, migrate.Validate(&d))\n\n\trequire.NoError(t, d.WriteFile(\"1.sql\", []byte(\"create table t(c int);\")))\n\tfiles, err = d.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 1)\n\trequire.Equal(t, \"1.sql\", files[0].Name())\n\trequire.Equal(t, \"1\", files[0].Version())\n\trequire.Equal(t, \"\", files[0].Desc())\n\trequire.EqualValues(t, \"create table t(c int);\", files[0].Bytes())\n\ths1, err := d.Checksum()\n\trequire.NoError(t, err)\n\ths2, err := migrate.NewHashFile(files)\n\trequire.NoError(t, err)\n\trequire.Equal(t, hs1, hs2)\n\n\t// Will fail without checksum file.\n\trequire.ErrorIs(t, migrate.Validate(&d), migrate.ErrChecksumNotFound)\n\n\t// Will not return the non-sql checksum file.\n\tfiles, err = d.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 1) // 1.sql\n\n\t// Sync with additional directory.\n\tvar d2, d3 migrate.MemDir\n\td.SyncWrites(d2.WriteFile, d3.WriteFile)\n\trequire.NoError(t, d.WriteFile(\"2.sql\", []byte(\"create table t2(c int);\")))\n\tfor _, d1 := range []migrate.MemDir{d, d2, d3} {\n\t\tf, err := d1.Open(\"2.sql\")\n\t\trequire.NoError(t, err)\n\t\tc, err := io.ReadAll(f)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"create table t2(c int);\", string(c))\n\t}\n}\n\nfunc TestOpenMemDir(t *testing.T) {\n\tdev1 := migrate.OpenMemDir(\"dev\")\n\trequire.NoError(t, dev1.WriteFile(\"1.sql\", []byte(\"create table t1(c int);\")))\n\t// Open the same dir.\n\tdev2 := migrate.OpenMemDir(\"dev\")\n\tfiles2, err := dev2.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files2, 1)\n\trequire.NoError(t, dev2.WriteFile(\"2.sql\", []byte(\"create table t2(c int);\")))\n\tfiles1, err := dev1.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files1, 2)\n\tfiles2, err = dev2.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files2, 2)\n\t// Open a new dir.\n\tetc := migrate.OpenMemDir(\"etc\")\n\tfiles, err := etc.Files()\n\trequire.NoError(t, err)\n\trequire.Empty(t, files)\n\n\t// Closing dir and opening it should not\n\t// clean it if there are active references.\n\trequire.NoError(t, dev1.Close())\n\tdev1 = migrate.OpenMemDir(\"dev\")\n\tfiles1, err = dev1.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files1, 2)\n\n\t// Cleanup directory on close.\n\trequire.NoError(t, dev1.Close())\n\trequire.NoError(t, dev2.Close())\n\tdev1 = migrate.OpenMemDir(\"dev\")\n\tfiles1, err = dev1.Files()\n\trequire.NoError(t, err)\n\trequire.Empty(t, files1)\n}\n\nfunc TestLocalFile_Directive(t *testing.T) {\n\tf := migrate.NewLocalFile(\"1.sql\", []byte(`-- atlas:lint ignore\nalter table users drop column id;\n`))\n\trequire.Empty(t, f.Directive(\"lint\"), \"statement directives are ignored\")\n\n\tf = migrate.NewLocalFile(\"1.sql\", []byte(`-- atlas:lint ignore\n\nalter table users drop column id;\n\n-- atlas:lint DS102\nalter table pets drop column id;\n`))\n\trequire.Equal(t, []string{\"ignore\"}, f.Directive(\"lint\"), \"single directive\")\n\n\tf = migrate.NewLocalFile(\"1.sql\", []byte(`-- atlas:lint ignore\n-- atlas:txmode none\n\nalter table users drop column id;\n\n-- atlas:lint DS102\nalter table pets drop column id;\n`))\n\trequire.Equal(t, []string{\"ignore\"}, f.Directive(\"lint\"), \"first directive from two\")\n\trequire.Equal(t, []string{\"none\"}, f.Directive(\"txmode\"), \"second directive from two\")\n\n\tf = migrate.NewLocalFile(\"1.sql\", []byte(`-- atlas:nolint\n\nalter table users drop column id;\n`))\n\trequire.Equal(t, []string{\"\"}, f.Directive(\"nolint\"), \"directives without arguments returned as empty string\")\n\n\tf = migrate.NewLocalFile(\"1.sql\", nil)\n\trequire.Empty(t, f.Directive(\"lint\"))\n\tf = migrate.NewLocalFile(\"1.sql\", []byte(\"-- atlas:lint ignore\"))\n\trequire.Empty(t, f.Directive(\"lint\"))\n\tf = migrate.NewLocalFile(\"1.sql\", []byte(\"-- atlas:lint ignore\\n\\n\"))\n\trequire.Equal(t, []string{\"ignore\"}, f.Directive(\"lint\"), \"double newline as directive separator\")\n\n\t// Multiple occurrences of the same directive.\n\tf = migrate.NewLocalFile(\"1.sql\", []byte(`-- atlas:import foo\n-- atlas:import\n-- atlas:import bar baz\n-- atlas:import qux\n-- atlas:import files_📄\n\nalter table users drop column id;\n`))\n\trequire.Equal(t, []string{\"foo\", \"\", \"bar baz\", \"qux\", \"files_📄\"}, f.Directive(\"import\"))\n\tf = migrate.NewLocalFile(\"1.sql\", []byte(\"-- atlas:import foo\\n\"))\n\trequire.Equal(t, []string{\"foo\"}, f.Directive(\"import\"))\n}\n\nfunc TestLocalFile_AddDirective(t *testing.T) {\n\tf := migrate.NewLocalFile(\"1.sql\", []byte(\"SELECT 1;\"))\n\tf.AddDirective(\"lint\", \"ignore\")\n\trequire.Equal(t, []string{\"ignore\"}, f.Directive(\"lint\"))\n\trequire.Equal(t, \"-- atlas:lint ignore\\n\\nSELECT 1;\", string(f.Bytes()))\n\tf.AddDirective(\"checkpoint\")\n\trequire.Equal(t, []string{\"ignore\"}, f.Directive(\"lint\"))\n\trequire.Equal(t, []string{\"\"}, f.Directive(\"checkpoint\"))\n\trequire.Equal(t, `-- atlas:checkpoint\n-- atlas:lint ignore\n\nSELECT 1;`, string(f.Bytes()))\n\n\tf = migrate.NewLocalFile(\"1.sql\", []byte(\"-- atlas:directive statement directive\\nSELECT 1;\"))\n\tf.AddDirective(\"lint\", \"ignore\")\n\trequire.Equal(t, []string{\"ignore\"}, f.Directive(\"lint\"))\n\trequire.Equal(t, `-- atlas:lint ignore\n\n-- atlas:directive statement directive\nSELECT 1;`, string(f.Bytes()))\n}\n\nfunc TestLocalFile_CheckpointTag(t *testing.T) {\n\t// Not a checkpoint.\n\tfor _, b := range []string{\n\t\t\"SELECT 1;\",\n\t\t\"-- atlas:checkpoint\\nSELECT 1;\",\n\t\t\"-- atlas:checkpoint tag\\nSELECT 1;\",\n\t} {\n\t\tf := migrate.NewLocalFile(\"1.sql\", []byte(b))\n\t\trequire.False(t, f.IsCheckpoint())\n\t\ttag, err := f.CheckpointTag()\n\t\trequire.ErrorIs(t, err, migrate.ErrNotCheckpoint)\n\t\trequire.Empty(t, tag)\n\t}\n\t// Checkpoint.\n\tf := migrate.NewLocalFile(\"1.sql\", []byte(\"-- atlas:checkpoint\\n\\nSELECT 1;\"))\n\trequire.True(t, f.IsCheckpoint())\n\ttag, err := f.CheckpointTag()\n\trequire.NoError(t, err)\n\trequire.Empty(t, tag)\n\tf = migrate.NewLocalFile(\"1.sql\", []byte(\"-- atlas:checkpoint tag\\n\\nSELECT 1;\"))\n\trequire.True(t, f.IsCheckpoint())\n\ttag, err = f.CheckpointTag()\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"tag\", tag)\n}\n\nfunc TestDirTar(t *testing.T) {\n\td := migrate.OpenMemDir(\"\")\n\tdefer d.Close()\n\n\terr := d.WriteFile(\"1.sql\", []byte(\"create table t(c int);\"))\n\trequire.NoError(t, err)\n\n\tb, err := migrate.ArchiveDir(d)\n\trequire.NoError(t, err)\n\tf, err := fileNames(bytes.NewReader(b))\n\trequire.NoError(t, err)\n\trequire.Equal(t, []string{\"1.sql\"}, f)\n\n\t// Test with Golang migrate dir.\n\tdir1, err := sqltool.NewGolangMigrateDir(\"./testdata/golang-migrate\")\n\trequire.NoError(t, err)\n\tb, err = migrate.ArchiveDir(dir1)\n\trequire.NoError(t, err)\n\n\t// With sumfile.\n\tchecksum, err := d.Checksum()\n\trequire.NoError(t, err)\n\terr = migrate.WriteSumFile(d, checksum)\n\trequire.NoError(t, err)\n\n\tb, err = migrate.ArchiveDir(d)\n\trequire.NoError(t, err)\n\tf, err = fileNames(bytes.NewReader(b))\n\trequire.NoError(t, err)\n\trequire.Equal(t, []string{\"atlas.sum\", \"1.sql\"}, f)\n\n\tdir, err := migrate.UnarchiveDir(b)\n\trequire.NoError(t, err)\n\tfiles, err := dir.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 1)\n\trequire.Equal(t, \"1.sql\", files[0].Name())\n\trequire.Equal(t, \"create table t(c int);\", string(files[0].Bytes()))\n\n\t// Compress the dir.\n\tvar buf bytes.Buffer\n\tw := gzip.NewWriter(&buf)\n\trequire.NoError(t, migrate.ArchiveDirTo(w, d))\n\trequire.NoError(t, w.Close()) // flush and Close.\n\n\t// Decompress.\n\trr, err := gzip.NewReader(&buf)\n\trequire.NoError(t, err)\n\tdir, err = migrate.UnarchiveDirFrom(rr)\n\trequire.NoError(t, err)\n\tfiles, err = dir.Files()\n\trequire.Len(t, files, 1)\n\trequire.Equal(t, \"1.sql\", files[0].Name())\n\trequire.Equal(t, \"create table t(c int);\", string(files[0].Bytes()))\n}\n\nfunc TestDefaultFormatter_FormatTo(t *testing.T) {\n\tvar b bytes.Buffer\n\terr := migrate.DefaultFormatter.FormatTo(&migrate.Plan{\n\t\tChanges: []*migrate.Change{\n\t\t\t{Cmd: \"create table t1(c int)\"},\n\t\t\t{Cmd: \"create table t2(c int)\", Comment: \"create table\"},\n\t\t},\n\t}, &b)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `create table t1(c int);\n-- Create table\ncreate table t2(c int);\n`, b.String())\n}\n\nfunc TestDefaultFormatter_Directives(t *testing.T) {\n\tvar (\n\t\tb bytes.Buffer\n\t\tp = &migrate.Plan{\n\t\t\tDirectives: []string{\"-- atlas:txmode none\"},\n\t\t\tChanges: []*migrate.Change{\n\t\t\t\t{Cmd: \"create table t1(c int)\"},\n\t\t\t\t{Cmd: \"create table t2(c int)\", Comment: \"create table\"},\n\t\t\t},\n\t\t}\n\t)\n\terr := migrate.DefaultFormatter.FormatTo(p, &b)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `-- atlas:txmode none\n\ncreate table t1(c int);\n-- Create table\ncreate table t2(c int);\n`, b.String())\n\n\tb.Reset()\n\tp.Delimiter = \"\\nGO\"\n\terr = migrate.DefaultFormatter.FormatTo(p, &b)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `-- atlas:delimiter \\nGO\n-- atlas:txmode none\n\ncreate table t1(c int)\nGO\n-- Create table\ncreate table t2(c int)\nGO\n`, b.String())\n\n\tb.Reset()\n\tp.Directives = append(p.Directives, \"-- atlas:nolint\")\n\terr = migrate.DefaultFormatter.FormatTo(p, &b)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `-- atlas:delimiter \\nGO\n-- atlas:txmode none\n-- atlas:nolint\n\ncreate table t1(c int)\nGO\n-- Create table\ncreate table t2(c int)\nGO\n`, b.String())\n}\n\nfunc TestDefaultFormatter_FormatFile(t *testing.T) {\n\tf, err := migrate.DefaultFormatter.FormatFile(&migrate.Plan{\n\t\tChanges: []*migrate.Change{\n\t\t\t{Cmd: \"create table t1(c int)\"},\n\t\t\t{Cmd: \"create table t2(c int)\", Comment: \"create table\"},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, `create table t1(c int);\n-- Create table\ncreate table t2(c int);\n`, string(f.Bytes()))\n\n\tft := migrate.TemplateFormatter{\n\t\t{\n\t\t\tN: template.Must(template.New(\"\").Parse(\"name-1\")),\n\t\t\tC: template.Must(template.New(\"\").Parse(\"cmd-1\")),\n\t\t},\n\t\t{\n\t\t\tN: template.Must(template.New(\"\").Parse(\"name-2\")),\n\t\t\tC: template.Must(template.New(\"\").Parse(\"cmd-2\")),\n\t\t},\n\t}\n\tf, err = ft.FormatFile(&migrate.Plan{})\n\trequire.Error(t, err, \"expect only one file\")\n\trequire.Nil(t, f)\n}\n\nfunc TestCheckVersion(t *testing.T) {\n\trequire.Error(t, migrate.CheckVersion(\"1\"))\n\trequire.NoError(t, migrate.CheckVersion(migrate.NewVersion()))\n}\n\nfunc fileNames(r io.Reader) ([]string, error) {\n\tvar out []string\n\ttr := tar.NewReader(r)\n\tfor {\n\t\thdr, err := tr.Next()\n\t\tif err == io.EOF {\n\t\t\tbreak // End of archive\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tout = append(out, hdr.Name)\n\t}\n\treturn out, nil\n}\n\nfunc removed(line, total, pos int, file string) *migrate.ChecksumError {\n\treturn reason(line, total, pos, file, migrate.ReasonRemoved)\n}\n\nfunc added(line, total, pos int, file string) *migrate.ChecksumError {\n\treturn reason(line, total, pos, file, migrate.ReasonAdded)\n}\n\nfunc edited(line, total, pos int, file string) *migrate.ChecksumError {\n\treturn reason(line, total, pos, file, migrate.ReasonEdited)\n}\n\nfunc reason(line, total, pos int, file string, reason migrate.Reason) *migrate.ChecksumError {\n\treturn &migrate.ChecksumError{\n\t\tLine:   line,\n\t\tPos:    pos,\n\t\tTotal:  total,\n\t\tFile:   file,\n\t\tReason: reason,\n\t}\n}\n"
  },
  {
    "path": "sql/migrate/lex.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage migrate\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\n// Stmt represents a scanned statement text along with its\n// position in the file and associated comments group.\ntype Stmt struct {\n\tPos      int      // statement position\n\tText     string   // statement text\n\tComments []string // associated comments\n}\n\n// Directive returns all directive comments with the given name.\n// See: pkg.go.dev/cmd/compile#hdr-Compiler_Directives.\nfunc (s *Stmt) Directive(name string) (ds []string) {\n\tfor _, c := range s.Comments {\n\t\tswitch {\n\t\tcase strings.HasPrefix(c, \"/*\") && !strings.Contains(c, \"\\n\"):\n\t\t\tif d, ok := directive(strings.TrimSuffix(c, \"*/\"), name, \"/*\"); ok {\n\t\t\t\tds = append(ds, d)\n\t\t\t}\n\t\tdefault:\n\t\t\tfor _, p := range []string{\"#\", \"--\", \"-- \"} {\n\t\t\t\tif d, ok := directive(c, name, p); ok {\n\t\t\t\t\tds = append(ds, d)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// Stmts provides a generic implementation for extracting SQL statements from the given file contents.\nfunc Stmts(input string) ([]*Stmt, error) {\n\treturn (&Scanner{\n\t\tScannerOptions: ScannerOptions{\n\t\t\t// Default options for backward compatibility.\n\t\t\tMatchBegin:       false,\n\t\t\tMatchBeginAtomic: true,\n\t\t\tMatchDollarQuote: true,\n\t\t},\n\t}).Scan(input)\n}\n\n// FileStmtDecls scans atlas-format file statements using\n// the Driver implementation, if implemented.\nfunc FileStmtDecls(drv Driver, f File) ([]*Stmt, error) {\n\ts, ok1 := drv.(StmtScanner)\n\t_, ok2 := f.(*LocalFile)\n\tif !ok1 || !ok2 {\n\t\treturn f.StmtDecls()\n\t}\n\treturn s.ScanStmts(string(f.Bytes()))\n}\n\n// FileStmts is like FileStmtDecls but returns only the\n// statement text without the extra info.\nfunc FileStmts(drv Driver, f File) ([]string, error) {\n\ts, err := FileStmtDecls(drv, f)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tstmts := make([]string, len(s))\n\tfor i := range s {\n\t\tstmts[i] = s[i].Text\n\t}\n\treturn stmts, nil\n}\n\ntype (\n\t// StmtScanner interface for scanning SQL statements from migration\n\t// and schema files and can be optionally implemented by drivers.\n\tStmtScanner interface {\n\t\tScanStmts(input string) ([]*Stmt, error)\n\t}\n\n\t// Scanner scanning SQL statements from migration and schema files.\n\tScanner struct {\n\t\tScannerOptions\n\t\t// scanner state.\n\t\tsrc, input string   // src and current input text\n\t\tpos        int      // current phase position\n\t\ttotal      int      // total bytes scanned so far\n\t\twidth      int      // size of latest rune\n\t\tdelim      string   // configured delimiter\n\t\tcomments   []string // collected comments\n\t\t// internal option to indicate if the\n\t\t// END word is parsed as a terminator.\n\t\tendterm *regexp.Regexp\n\t}\n\n\t// ScannerOptions controls the behavior of the scanner.\n\tScannerOptions struct {\n\t\t// MatchBegin enables matching for BEGIN ... END statements block.\n\t\tMatchBegin bool\n\t\t// MatchBeginAtomic enables matching for BEGIN ATOMIC ... END statements block.\n\t\tMatchBeginAtomic bool\n\t\t// MatchBeginCatch enables matching for BEGIN TRY/CATCH ... END TRY/CATCH statements block.\n\t\tMatchBeginTryCatch bool\n\t\t// MatchDollarQuote enables the PostgreSQL dollar-quoted string syntax.\n\t\tMatchDollarQuote bool\n\t\t// BackslashEscapes enables backslash-escaped strings. By default, only MySQL/MariaDB uses backslash as\n\t\t// an escape character.  https://dev.mysql.com/doc/refman/8.4/en/sql-mode.html#sqlmode_no_backslash_escapes\n\t\tBackslashEscapes bool\n\t\t// EscapedStringExt enables the supported for PG extension for escaped strings and adopted by its flavors.\n\t\t// See: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE.\n\t\tEscapedStringExt bool\n\t\t// HashComments enables MySQL/MariaDB hash-like (#) comments.\n\t\tHashComments bool\n\t\t// Enable the \"GO\" command as a delimiter.\n\t\tGoCommand bool\n\t\t// BeginEndTerminator is a T-SQL specific option that allows\n\t\t// the scanner to terminate BEGIN/END blocks with a semicolon.\n\t\tBeginEndTerminator bool\n\t\t// omit delimiter from the statement\n\t\tOmitDelimiter bool\n\t}\n)\n\n// Scan scans the statement in the given input.\nfunc (s *Scanner) Scan(input string) ([]*Stmt, error) {\n\tvar stmts []*Stmt\n\tif err := s.init(input); err != nil {\n\t\treturn nil, err\n\t}\n\tfor {\n\t\ts, err := s.stmt()\n\t\tif err == io.EOF {\n\t\t\treturn stmts, nil\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tstmts = append(stmts, s)\n\t}\n}\n\n// init initializes the scanner state.\nfunc (s *Scanner) init(input string) error {\n\ts.comments = nil\n\ts.pos, s.total, s.width = 0, 0, 0\n\ts.src, s.input, s.delim = input, input, delimiter\n\tif d, ok := directive(input, directiveDelimiter, directivePrefixSQL); ok {\n\t\tif err := s.setDelim(d); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tparts := strings.SplitN(input, \"\\n\", 2)\n\t\tif len(parts) == 1 {\n\t\t\treturn s.error(s.pos, \"no input found after delimiter %q\", d)\n\t\t}\n\t\ts.input = parts[1]\n\t}\n\treturn nil\n}\n\nconst (\n\teos          = -1\n\tdelimiter    = \";\"\n\tdelimiterCmd = \"delimiter\"\n)\n\nvar (\n\t// Dollar-quoted string as defined by the PostgreSQL scanner.\n\treDollarQuote = regexp.MustCompile(`^\\$([A-Za-zÈ-ÿ_][\\wÈ-ÿ]*)*\\$`)\n\t// The 'BEGIN ATOMIC' syntax as specified in the SQL 2003 standard.\n\treBeginAtomic = regexp.MustCompile(`(?i)^\\s*BEGIN\\s+ATOMIC\\s+`)\n\treBeginTry    = regexp.MustCompile(`(?i)^\\s*BEGIN\\s+TRY\\s+`)\n\treBegin       = regexp.MustCompile(`(?i)^\\s*BEGIN\\s+`)\n\treEnd         = regexp.MustCompile(`(?i)^\\s*END\\s*`)\n\treEndCatch    = regexp.MustCompile(`(?i)^\\s*END\\s*CATCH\\s*`)\n\treGoCmd       = regexp.MustCompile(`(?i)^GO(?:\\s+|$)`)\n)\n\nfunc (s *Scanner) stmt() (*Stmt, error) {\n\tvar (\n\t\tdepth, openingPos int\n\t\ttext              string\n\t)\n\ts.skipSpaces()\nScan:\n\tfor {\n\t\tswitch r := s.next(); {\n\t\tcase r == eos:\n\t\t\tswitch {\n\t\t\tcase depth > 0:\n\t\t\t\treturn nil, s.error(openingPos, \"unclosed '('\")\n\t\t\tcase s.pos > 0:\n\t\t\t\ttext = s.input\n\t\t\t\tbreak Scan\n\t\t\tdefault:\n\t\t\t\treturn nil, io.EOF\n\t\t\t}\n\t\tcase r == '(':\n\t\t\tif depth == 0 {\n\t\t\t\topeningPos = s.pos\n\t\t\t}\n\t\t\tdepth++\n\t\tcase r == ')':\n\t\t\tif depth == 0 {\n\t\t\t\treturn nil, s.error(s.pos, \"unexpected ')'\")\n\t\t\t}\n\t\t\tdepth--\n\t\tcase r == '\\'', r == '\"', r == '`':\n\t\t\tif err := s.skipQuote(r); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t// Check if the start of the statement is the MySQL DELIMITER command.\n\t\t// See https://dev.mysql.com/doc/refman/8.0/en/mysql-commands.html.\n\t\tcase s.pos == 1 && len(s.input) > len(delimiterCmd) && strings.EqualFold(s.input[:len(delimiterCmd)], delimiterCmd):\n\t\t\ts.addPos(len(delimiterCmd) - 1)\n\t\t\tif err := s.delimCmd(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ts.skipSpaces()\n\t\t// GO command takes over the delimiter '\\nGO'\n\t\t// in cases it can't parse the statements correctly.\n\t\tcase s.GoCommand && r == '\\n' && reGoCmd.MatchString(s.input[s.pos:]):\n\t\t\ts.next() // skip '\\n'\n\t\t\tfallthrough\n\t\tcase s.GoCommand && (s.pos == 1 || s.pos > 1 && s.input[s.pos-2] == '\\n') && reGoCmd.MatchString(s.input[s.pos-1:]):\n\t\t\ttext = s.input[:s.pos-1]\n\t\t\ts.next() // skip 'O'\n\t\t\tif err := s.skipGoCount(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ts.skipSpaces()\n\t\t\tbreak Scan\n\t\t// Delimiters take precedence over comments.\n\t\tcase depth == 0 && strings.HasPrefix(s.input[s.pos-s.width:], s.delim):\n\t\t\ts.addPos(len(s.delim) - s.width)\n\t\t\ttext = s.input[:s.pos]\n\t\t\tbreak Scan\n\t\tcase s.MatchDollarQuote && r == '$' && reDollarQuote.MatchString(s.input[s.pos-1:]):\n\t\t\tif err := s.skipDollarQuote(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tcase r == '#' && s.HashComments:\n\t\t\ts.comment(\"#\", \"\\n\")\n\t\tcase r == '-' && s.pick() == '-':\n\t\t\ts.next()\n\t\t\ts.comment(\"--\", \"\\n\")\n\t\tcase r == '/' && s.pick() == '*':\n\t\t\ts.next()\n\t\t\ts.comment(\"/*\", \"*/\")\n\t\tcase s.endterm != nil && s.endterm.MatchString(s.input[:s.pos]):\n\t\t\ttext = s.input[:s.pos]\n\t\t\tbreak Scan\n\t\tcase s.delim == delimiter && s.MatchBeginAtomic && reBeginAtomic.MatchString(s.input[s.pos-1:]):\n\t\t\tif err := s.skipBeginAtomic(); err == nil {\n\t\t\t\ttext = s.input[:s.pos]\n\t\t\t\tbreak Scan\n\t\t\t}\n\t\t\t// Not a \"BEGIN ATOMIC\" block.\n\t\tcase s.delim == delimiter && s.MatchBeginTryCatch && reBeginTry.MatchString(s.input[s.pos-1:]):\n\t\t\tif err := s.skipBeginTryCatch(); err == nil {\n\t\t\t\ttext = s.input[:s.pos]\n\t\t\t\tbreak Scan\n\t\t\t}\n\t\t\t// Not a \"BEGIN TRY ... END CATCH\" block.\n\t\tcase s.delim == delimiter && s.MatchBegin &&\n\t\t\t// Either the current scanned statement starts with BEGIN, or we inside a statement and expects at least one ~space before).\n\t\t\t(s.pos == 1 && reBegin.MatchString(s.input[s.pos-1:]) || s.pos > 1 && reBegin.MatchString(s.input[s.pos-2:])):\n\t\t\tif err := s.skipBegin(); err == nil {\n\t\t\t\ttext = s.input[:s.pos]\n\t\t\t\tbreak Scan\n\t\t\t}\n\t\t\t// Not a \"BEGIN\" block.\n\t\t}\n\t}\n\treturn s.emit(text), nil\n}\n\nfunc (s *Scanner) next() rune {\n\tif s.pos >= len(s.input) {\n\t\treturn eos\n\t}\n\tr, w := utf8.DecodeRuneInString(s.input[s.pos:])\n\ts.width = w\n\ts.addPos(w)\n\treturn r\n}\n\nfunc (s *Scanner) pick() rune {\n\tp, w, t := s.pos, s.width, s.total\n\tr := s.next()\n\ts.pos, s.width, s.total = p, w, t\n\treturn r\n}\n\nfunc (s *Scanner) addPos(p int) {\n\ts.pos += p\n\ts.total += p\n}\n\nfunc (s *Scanner) skipQuote(quote rune) error {\n\tvar (\n\t\tpos     = s.pos\n\t\tescaped = s.BackslashEscapes || s.EscapedStringExt && s.pos > 0 && (s.input[s.pos-1] == 'E' || s.input[s.pos-1] == 'e')\n\t)\n\tfor {\n\t\tswitch r := s.next(); {\n\t\tcase r == eos:\n\t\t\treturn s.error(pos, \"unclosed quote %q\", quote)\n\t\tcase r == '\\\\' && escaped:\n\t\t\ts.next()\n\t\tcase r == quote:\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (s *Scanner) skipDollarQuote() error {\n\tm := reDollarQuote.FindString(s.input[s.pos-1:])\n\tif m == \"\" {\n\t\treturn s.error(s.pos, \"unexpected dollar quote\")\n\t}\n\ts.addPos(len(m) - 1)\n\tfor {\n\t\tswitch r := s.next(); {\n\t\tcase r == eos:\n\t\t\t// Fail only if a delimiter was not set.\n\t\t\tif s.delim == \"\" {\n\t\t\t\treturn s.error(s.pos, \"unclosed dollar-quoted string\")\n\t\t\t}\n\t\t\treturn nil\n\t\tcase r == '$' && strings.HasPrefix(s.input[s.pos-1:], m):\n\t\t\ts.addPos(len(m) - 1)\n\t\t\treturn nil\n\t\t}\n\t}\n}\n\nfunc (s *Scanner) skipBeginAtomic() error {\n\tm := reBeginAtomic.FindString(s.input[s.pos-1:])\n\tif m == \"\" {\n\t\treturn s.error(s.pos, \"unexpected missing BEGIN ATOMIC block\")\n\t}\n\ts.addPos(len(m) - 1)\n\tbody := &Scanner{ScannerOptions: s.ScannerOptions}\n\tif err := body.init(s.input[s.pos:]); err != nil {\n\t\treturn err\n\t}\n\tfor {\n\t\tstmt, err := body.stmt()\n\t\tif err == io.EOF {\n\t\t\treturn s.error(s.pos, \"unexpected eof when scanning sql body\")\n\t\t}\n\t\tif err != nil {\n\t\t\treturn s.error(s.pos, \"scan sql body: %v\", err)\n\t\t}\n\t\tif reEnd.MatchString(stmt.Text) {\n\t\t\tbreak\n\t\t}\n\t}\n\ts.addPos(body.total)\n\treturn nil\n}\n\nfunc (s *Scanner) skipBeginTryCatch() error {\n\tm := reBeginTry.FindString(s.input[s.pos-1:])\n\tif m == \"\" {\n\t\treturn s.error(s.pos, \"unexpected missing BEGIN TRY block\")\n\t}\n\ts.addPos(len(m) - 1)\n\tbody := &Scanner{ScannerOptions: s.ScannerOptions}\n\tif err := body.init(s.input[s.pos:]); err != nil {\n\t\treturn err\n\t}\n\tfor {\n\t\tstmt, err := body.stmt()\n\t\tif err == io.EOF {\n\t\t\treturn s.error(s.pos, \"unexpected eof when scanning sql body\")\n\t\t}\n\t\tif err != nil {\n\t\t\treturn s.error(s.pos, \"scan sql body: %v\", err)\n\t\t}\n\t\tif end := reEndCatch.FindString(stmt.Text); end != \"\" {\n\t\t\t// In case \"END CATCH\" is not followed by a semicolon (\\n instead),\n\t\t\t// backup the extra consumed statement (it might be END;) and exit.\n\t\t\tif !strings.HasSuffix(strings.TrimSpace(end), \";\") {\n\t\t\t\ts.addPos(-(len(stmt.Text) - len(end)))\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\ts.addPos(body.total)\n\treturn nil\n}\n\nvar (\n\treEndTerm = regexp.MustCompile(`(?i)\\s*END\\s*$`)\n)\n\nfunc (s *Scanner) skipBegin() error {\n\tm := reBegin.FindString(s.input[s.pos-1:])\n\tif m == \"\" {\n\t\treturn s.error(s.pos, \"unexpected missing BEGIN block\")\n\t}\n\ts.addPos(len(m) - 1)\n\tgroup := &Scanner{ScannerOptions: s.ScannerOptions}\n\tif s.BeginEndTerminator {\n\t\tgroup.endterm = reEndTerm\n\t}\n\tif err := group.init(s.input[s.pos:]); err != nil {\n\t\treturn err\n\t}\nLoop:\n\tfor {\n\t\tswitch stmt, err := group.stmt(); {\n\t\tcase err == io.EOF:\n\t\t\treturn s.error(s.pos, \"unexpected eof when scanning compound statements\")\n\t\tcase err != nil:\n\t\t\treturn s.error(s.pos, \"scan compound statements: %v\", err)\n\t\tcase reEnd.MatchString(stmt.Text):\n\t\t\tif m := reEnd.FindString(stmt.Text); len(m) == len(stmt.Text) || strings.TrimPrefix(stmt.Text, m) == s.delim {\n\t\t\t\tbreak Loop\n\t\t\t}\n\t\tcase s.BeginEndTerminator && reEndTerm.MatchString(stmt.Text):\n\t\t\tbreak Loop\n\t\t}\n\t}\n\ts.addPos(group.total)\n\treturn nil\n}\n\nfunc (s *Scanner) comment(left, right string) {\n\ti := strings.Index(s.input[s.pos:], right)\n\t// Not a comment.\n\tif i == -1 {\n\t\treturn\n\t}\n\t// If the comment reside inside a statement, collect it.\n\tif s.pos != len(left) {\n\t\ts.addPos(i + len(right))\n\t\treturn\n\t}\n\ts.addPos(i + len(right))\n\t// If we did not scan any statement characters, it\n\t// can be skipped and stored in the comments group.\n\ts.comments = append(s.comments, s.input[:s.pos])\n\ts.input = s.input[s.pos:]\n\ts.pos = 0\n\t// Double \\n separate the comments group from the statement.\n\tif strings.HasPrefix(s.input, \"\\n\\n\") || right == \"\\n\" && strings.HasPrefix(s.input, \"\\n\") {\n\t\ts.comments = nil\n\t}\n\ts.skipSpaces()\n}\n\nfunc (s *Scanner) skipSpaces() {\n\tn := len(s.input)\n\ts.input = strings.TrimLeftFunc(s.input, unicode.IsSpace)\n\ts.total += n - len(s.input)\n}\n\nfunc (s *Scanner) emit(text string) *Stmt {\n\tstmt := &Stmt{Pos: s.total - len(text), Text: text, Comments: s.comments}\n\ts.input = s.input[s.pos:]\n\ts.pos = 0\n\ts.comments = nil\n\t// Trim delimiter if requested or is not the default one.\n\tif s.OmitDelimiter || s.delim != delimiter {\n\t\tstmt.Text = strings.TrimSuffix(stmt.Text, s.delim)\n\t}\n\tstmt.Text = strings.TrimSpace(stmt.Text)\n\treturn stmt\n}\n\n// delimCmd checks if the scanned \"DELIMITER\"\n// text represents an actual delimiter command.\nfunc (s *Scanner) delimCmd() error {\n\t// A space must come after the delimiter.\n\tif s.pick() != ' ' {\n\t\treturn nil\n\t}\n\t// Scan delimiter.\n\tfor r := s.pick(); r != eos && r != '\\n'; r = s.next() {\n\t}\n\tdelim := strings.TrimSpace(s.input[len(delimiterCmd):s.pos])\n\t// MySQL client allows quoting delimiters.\n\tif strings.HasPrefix(delim, \"'\") && strings.HasSuffix(delim, \"'\") {\n\t\tdelim = strings.ReplaceAll(delim[1:len(delim)-1], \"''\", \"'\")\n\t}\n\tif err := s.setDelim(delim); err != nil {\n\t\treturn err\n\t}\n\t// Skip all we saw until now.\n\ts.emit(s.input[:s.pos])\n\treturn nil\n}\n\n// skipGoCount checks if the scanned \"GO\"\nfunc (s *Scanner) skipGoCount() (err error) {\n\t// GO [count]\\n\n\tif s.pick() == ' ' {\n\t\tc := s.pos\n\t\t// Scan [count]\\n\n\t\tfor r := s.pick(); r != eos && r != '\\n'; {\n\t\t\tr = s.next()\n\t\t}\n\t\t_, err := strconv.Atoi(strings.TrimSpace(s.input[c:s.pos]))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"sql/migrate: invalid GO command, expect digits got %q: %w\",\n\t\t\t\ts.input[c:s.pos], err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *Scanner) setDelim(d string) error {\n\tif d == \"\" {\n\t\treturn errors.New(\"empty delimiter\")\n\t}\n\t// Unescape delimiters. e.g. \"\\\\n\" => \"\\n\".\n\ts.delim = strings.NewReplacer(`\\n`, \"\\n\", `\\r`, \"\\r\", `\\t`, \"\\t\").Replace(d)\n\treturn nil\n}\n\nfunc (s *Scanner) error(pos int, format string, args ...any) error {\n\tformat = \"%d:%d: \" + format\n\tvar (\n\t\tp    = len(s.src) - len(s.input) + pos\n\t\tsrc  = s.src[:p]\n\t\tcol  = strings.LastIndex(src, \"\\n\")\n\t\tline = 1 + strings.Count(src, \"\\n\")\n\t)\n\tif line == 1 {\n\t\tcol = p\n\t} else {\n\t\tcol = p - col - 1\n\t}\n\treturn fmt.Errorf(format, append([]any{line, col}, args...)...)\n}\n"
  },
  {
    "path": "sql/migrate/lex_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage migrate\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLocalFile_Stmts(t *testing.T) {\n\tpath := filepath.Join(\"testdata\", \"lex\")\n\tdir, err := NewLocalDir(path)\n\trequire.NoError(t, err)\n\tfiles, err := dir.Files()\n\trequire.NoError(t, err)\n\tfor _, f := range files {\n\t\tsc := &Scanner{\n\t\t\tScannerOptions: ScannerOptions{\n\t\t\t\tMatchBegin:       true,\n\t\t\t\tMatchBeginAtomic: true,\n\t\t\t\tMatchDollarQuote: true,\n\t\t\t\tBackslashEscapes: true,\n\t\t\t\tEscapedStringExt: true,\n\t\t\t\tHashComments:     !strings.Contains(f.Name(), \"_pg\"),\n\t\t\t\tGoCommand:        strings.Contains(f.Name(), \"_ms\"),\n\t\t\t},\n\t\t}\n\t\tdecls, err := sc.Scan(string(f.Bytes()))\n\t\trequire.NoErrorf(t, err, \"file: %s\", f.Name())\n\t\tbuf, err := os.ReadFile(filepath.Join(path, f.Name()+\".golden\"))\n\t\trequire.NoError(t, err)\n\t\tstmts := make([]string, len(decls))\n\t\tfor i, s := range decls {\n\t\t\tstmts[i] = s.Text\n\t\t}\n\t\trequire.Equalf(t, string(buf), strings.Join(stmts, \"\\n-- end --\\n\"), \"mismatched statements in file %q\", f.Name())\n\t}\n}\n\nfunc TestScanner_StmtsGroup(t *testing.T) {\n\tscan := &Scanner{}\n\tscan.MatchBegin = true\n\tpath := filepath.Join(\"testdata\", \"lexgroup\")\n\tdir, err := NewLocalDir(path)\n\trequire.NoError(t, err)\n\tfiles, err := dir.Files()\n\trequire.NoError(t, err)\n\tfor _, f := range files {\n\t\tstmts, err := scan.Scan(string(f.Bytes()))\n\t\trequire.NoErrorf(t, err, \"file: %s\", f.Name())\n\t\tbuf, err := os.ReadFile(filepath.Join(path, f.Name()+\".golden\"))\n\t\trequire.NoError(t, err)\n\t\tgot := make([]string, len(stmts))\n\t\tfor i, s := range stmts {\n\t\t\tgot[i] = s.Text\n\t\t}\n\t\trequire.Equalf(t, string(buf), strings.Join(got, \"\\n-- end --\\n\"), \"mismatched statements in file %q\", f.Name())\n\t}\n}\n\nfunc TestScanner_EscapedStrings(t *testing.T) {\n\tpath := filepath.Join(\"testdata\", \"lexescaped\")\n\tdir, err := NewLocalDir(path)\n\trequire.NoError(t, err)\n\tfiles, err := dir.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 2, \"tests should be updated\")\n\tscan := &Scanner{}\n\tscan.BackslashEscapes = true\n\tstmts, err := scan.Scan(string(files[0].Bytes()))\n\trequire.NoError(t, err)\n\tbuf, err := os.ReadFile(filepath.Join(path, files[0].Name()+\".golden\"))\n\trequire.NoError(t, err)\n\tgot := make([]string, len(stmts))\n\tfor i, s := range stmts {\n\t\tgot[i] = s.Text\n\t}\n\trequire.Equalf(t, string(buf), strings.Join(got, \"\\n-- end --\\n\"), \"mismatched statements in file %q\", files[0].Name())\n\t_, err = scan.Scan(string(files[1].Bytes()))\n\trequire.EqualError(t, err, `4:40: unclosed quote '\\''`, \"escaped strings conflicts with standard strings\")\n\n\tscan.BackslashEscapes = false\n\tscan.EscapedStringExt = true\n\tstmts, err = scan.Scan(string(files[0].Bytes()))\n\trequire.EqualError(t, err, `4:42: unclosed quote '\\''`, \"disabled escaped strings should fail parse of escaped strings without the extension\")\n\tstmts, err = scan.Scan(string(files[1].Bytes()))\n\trequire.NoError(t, err)\n\tbuf, err = os.ReadFile(filepath.Join(path, files[1].Name()+\".golden\"))\n\trequire.NoError(t, err)\n\tgot = make([]string, len(stmts))\n\tfor i, s := range stmts {\n\t\tgot[i] = s.Text\n\t}\n\trequire.Equalf(t, string(buf), strings.Join(got, \"\\n-- end --\\n\"), \"mismatched statements in file %q\", files[1].Name())\n}\n\nfunc TestScanner_BeginTryCatch(t *testing.T) {\n\tpath := filepath.Join(\"testdata\", \"lexbegintry\")\n\tdir, err := NewLocalDir(path)\n\trequire.NoError(t, err)\n\tfiles, err := dir.Files()\n\trequire.NoError(t, err)\n\tfor _, f := range files {\n\t\tsc := &Scanner{\n\t\t\tScannerOptions: ScannerOptions{\n\t\t\t\tMatchBegin:         true,\n\t\t\t\tMatchBeginAtomic:   true,\n\t\t\t\tMatchBeginTryCatch: true,\n\t\t\t\tMatchDollarQuote:   true,\n\t\t\t\tBackslashEscapes:   true,\n\t\t\t\tEscapedStringExt:   true,\n\t\t\t\tHashComments:       false,\n\t\t\t},\n\t\t}\n\t\tdecls, err := sc.Scan(string(f.Bytes()))\n\t\trequire.NoErrorf(t, err, \"file: %s\", f.Name())\n\t\tbuf, err := os.ReadFile(filepath.Join(path, f.Name()+\".golden\"))\n\t\trequire.NoError(t, err)\n\t\tstmts := make([]string, len(decls))\n\t\tfor i, s := range decls {\n\t\t\tstmts[i] = s.Text\n\t\t}\n\t\trequire.Equalf(t, string(buf), strings.Join(stmts, \"\\n-- end --\\n\"), \"mismatched statements in file %q\", f.Name())\n\t}\n}\n\nfunc TestScanner_SQLServer(t *testing.T) {\n\tscan := &Scanner{}\n\tscan.MatchBegin = true\n\tscan.BeginEndTerminator = true\n\tpath := filepath.Join(\"testdata\", \"sqlserver\")\n\tdir, err := NewLocalDir(path)\n\trequire.NoError(t, err)\n\tfiles, err := dir.Files()\n\trequire.NoError(t, err)\n\tfor _, f := range files {\n\t\tstmts, err := scan.Scan(string(f.Bytes()))\n\t\trequire.NoErrorf(t, err, \"file: %s\", f.Name())\n\t\tbuf, err := os.ReadFile(filepath.Join(path, f.Name()+\".golden\"))\n\t\trequire.NoError(t, err)\n\t\tgot := make([]string, len(stmts))\n\t\tfor i, s := range stmts {\n\t\t\tgot[i] = s.Text\n\t\t}\n\t\trequire.Equalf(t, string(buf), strings.Join(got, \"\\n-- end --\\n\"), \"mismatched statements in file %q\", f.Name())\n\t}\n}\n\nfunc TestLocalFile_StmtDecls(t *testing.T) {\n\tf := `cmd0;\n-- test\ncmd1;\n\n-- hello\n-- world\ncmd2;\n\n-- skip\n-- this\n# comment\n\n/* Skip this as well */\n\n# Skip this\n/* one */\n\n# command\ncmd3;\n\n/* comment1 */\n/* comment2 */\ncmd4;\n\n--atlas:nolint\n-- atlas:nolint destructive\ncmd5;\n\n#atlas:lint error\n/*atlas:nolint DS101*/\n/* atlas:lint not a directive */\n/*\natlas:lint not a directive\n*/\ncmd6;\n\n-- atlas:nolint\ncmd7;\n`\n\tsc := &Scanner{\n\t\tScannerOptions: ScannerOptions{\n\t\t\tMatchBegin:       true,\n\t\t\tMatchBeginAtomic: true,\n\t\t\tMatchDollarQuote: true,\n\t\t\tBackslashEscapes: true,\n\t\t\tEscapedStringExt: true,\n\t\t\tHashComments:     true,\n\t\t},\n\t}\n\tstmts, err := sc.Scan(f)\n\trequire.NoError(t, err)\n\trequire.Len(t, stmts, 8)\n\n\trequire.Equal(t, \"cmd0;\", stmts[0].Text)\n\trequire.Equal(t, 0, stmts[0].Pos, \"start of the file\")\n\n\trequire.Equal(t, \"cmd1;\", stmts[1].Text)\n\trequire.Equal(t, strings.Index(f, \"cmd1;\"), stmts[1].Pos)\n\trequire.Equal(t, []string{\"-- test\\n\"}, stmts[1].Comments)\n\n\trequire.Equal(t, \"cmd2;\", stmts[2].Text)\n\trequire.Equal(t, strings.Index(f, \"cmd2;\"), stmts[2].Pos)\n\trequire.Equal(t, []string{\"-- hello\\n\", \"-- world\\n\"}, stmts[2].Comments)\n\n\trequire.Equal(t, \"cmd3;\", stmts[3].Text)\n\trequire.Equal(t, strings.Index(f, \"cmd3;\"), stmts[3].Pos)\n\trequire.Equal(t, []string{\"# command\\n\"}, stmts[3].Comments)\n\n\trequire.Equal(t, \"cmd4;\", stmts[4].Text)\n\trequire.Equal(t, strings.Index(f, \"cmd4;\"), stmts[4].Pos)\n\trequire.Equal(t, []string{\"/* comment1 */\", \"/* comment2 */\"}, stmts[4].Comments)\n\n\trequire.Equal(t, \"cmd5;\", stmts[5].Text)\n\trequire.Equal(t, strings.Index(f, \"cmd5;\"), stmts[5].Pos)\n\trequire.Equal(t, []string{\"--atlas:nolint\\n\", \"-- atlas:nolint destructive\\n\"}, stmts[5].Comments)\n\trequire.Equal(t, []string{\"\", \"destructive\"}, stmts[5].Directive(\"nolint\"))\n\n\trequire.Equal(t, \"cmd6;\", stmts[6].Text)\n\trequire.Equal(t, strings.Index(f, \"cmd6;\"), stmts[6].Pos)\n\trequire.Equal(t, []string{\"#atlas:lint error\\n\", \"/*atlas:nolint DS101*/\", \"/* atlas:lint not a directive */\", \"/*\\natlas:lint not a directive\\n*/\"}, stmts[6].Comments)\n\trequire.Equal(t, []string{\"error\"}, stmts[6].Directive(\"lint\"))\n\trequire.Equal(t, []string{\"DS101\"}, stmts[6].Directive(\"nolint\"))\n\n\trequire.Equal(t, \"cmd7;\", stmts[7].Text)\n\trequire.Equal(t, []string{\"\"}, stmts[7].Directive(\"nolint\"))\n}\n\nfunc TestLex_Errors(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname, stmt, err string\n\t}{\n\t\t{\n\t\t\tname: \"unclosed single at 1:1\",\n\t\t\tstmt: \"'this quote is unclosed at 1:1\",\n\t\t\terr:  \"1:1: unclosed quote '\\\\''\",\n\t\t},\n\t\t{\n\t\t\tname: \"unclosed single at 1:6\",\n\t\t\tstmt: \"12345'this quote is unclosed at pos 7\",\n\t\t\terr:  \"1:6: unclosed quote '\\\\''\",\n\t\t},\n\t\t{\n\t\t\tname: \"unclosed single at EOS\",\n\t\t\tstmt: \"unclosed '\",\n\t\t\terr:  \"1:10: unclosed quote '\\\\''\",\n\t\t},\n\t\t{\n\t\t\tname: \"unclosed double at 1:1\",\n\t\t\tstmt: \"\\\"unclosed double\",\n\t\t\terr:  \"1:1: unclosed quote '\\\"'\",\n\t\t},\n\t\t{\n\t\t\tname: \"unclosed double at 2:2\",\n\t\t\tstmt: \"unclosed double at 2:2\\n \\\"\",\n\t\t\terr:  \"2:2: unclosed quote '\\\"'\",\n\t\t},\n\t\t{\n\t\t\tname: \"unclosed double at 5:5\",\n\t\t\tstmt: \"unclosed double at 2:2\\n\\n\\n\\n1234\\\"\",\n\t\t\terr:  \"5:5: unclosed quote '\\\"'\",\n\t\t},\n\t\t{\n\t\t\tname: \"unclosed parentheses at 1:1\",\n\t\t\tstmt: \"(unclosed parentheses\",\n\t\t\terr:  \"1:1: unclosed '('\",\n\t\t},\n\t\t{\n\t\t\tname: \"unclosed parentheses at 1:3\",\n\t\t\tstmt: \"()(unclosed parentheses\",\n\t\t\terr:  \"1:3: unclosed '('\",\n\t\t},\n\t\t{\n\t\t\tname: \"unexpected parentheses at 1:5\",\n\t\t\tstmt: \"1234)6789\",\n\t\t\terr:  \"1:5: unexpected ')'\",\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t_, err := Stmts(tt.stmt)\n\t\t\trequire.EqualError(t, err, tt.err)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "sql/migrate/migrate.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage migrate\n\nimport (\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/schema\"\n)\n\ntype (\n\t// A Plan defines a planned changeset that its execution brings the database to\n\t// the new desired state. Additional information is calculated by the different\n\t// drivers to indicate if the changeset is transactional (can be rolled-back) and\n\t// reversible (a down file can be generated to it).\n\tPlan struct {\n\t\t// Version and Name of the plan. Provided by the user or auto-generated.\n\t\tVersion, Name string\n\n\t\t// Reversible describes if the changeset is reversible.\n\t\tReversible bool\n\n\t\t// Transactional describes if the changeset is transactional.\n\t\tTransactional bool\n\n\t\t// Changes defines the list of changeset in the plan.\n\t\tChanges []*Change\n\n\t\t// Delimiter to use for separating statements.\n\t\tDelimiter string\n\n\t\t// Directives to add to the file (not associated with any statements) besides the delimiter.\n\t\t// For example, atlas:txtar, atlas:txmode, etc.\n\t\tDirectives []string\n\t}\n\n\t// A Change of migration.\n\tChange struct {\n\t\t// Cmd or statement to execute.\n\t\tCmd string\n\n\t\t// Args for placeholder parameters in the statement above.\n\t\tArgs []any\n\n\t\t// A Comment describes the change.\n\t\tComment string\n\n\t\t// Reverse contains the \"reversed\" statement(s) if\n\t\t// the command is reversible.\n\t\tReverse any // string | []string\n\n\t\t// The Source that caused this change, or nil.\n\t\tSource schema.Change\n\t}\n)\n\n// AddDirectiveOnce adds the given directive to the plan if it does not exist.\nfunc (p *Plan) AddDirectiveOnce(d string) {\n\tif !slices.Contains(p.Directives, d) {\n\t\tp.Directives = append(p.Directives, d)\n\t}\n}\n\n// ReverseStmts returns the reverse statements of a Change, if any.\nfunc (c *Change) ReverseStmts() (cmd []string, err error) {\n\tswitch r := c.Reverse.(type) {\n\tcase nil:\n\tcase string:\n\t\tcmd = []string{r}\n\tcase []string:\n\t\tcmd = r\n\tdefault:\n\t\terr = fmt.Errorf(\"sql/migrate: unexpected type %T for reverse commands\", r)\n\t}\n\treturn\n}\n\ntype (\n\t// The Driver interface must be implemented by the different dialects to support database\n\t// migration authoring/planning and applying. ExecQuerier, Inspector and Differ, provide\n\t// basic schema primitives for inspecting database schemas, calculate the difference between\n\t// schema elements, and executing raw SQL statements. The PlanApplier interface wraps the\n\t// methods for generating migration plan for applying the actual changes on the database.\n\tDriver interface {\n\t\tschema.Differ\n\t\tschema.ExecQuerier\n\t\tschema.Inspector\n\t\tschema.Locker\n\t\tPlanApplier\n\t\tSnapshoter\n\t\tCleanChecker\n\t}\n\n\t// PlanApplier wraps the methods for planning and applying changes\n\t// on the database.\n\tPlanApplier interface {\n\t\t// PlanChanges returns a migration plan for applying the given changeset.\n\t\tPlanChanges(context.Context, string, []schema.Change, ...PlanOption) (*Plan, error)\n\n\t\t// ApplyChanges is responsible for applying the given changeset.\n\t\t// An error may return from ApplyChanges if the driver is unable\n\t\t// to execute a change.\n\t\tApplyChanges(context.Context, []schema.Change, ...PlanOption) error\n\t}\n\n\t// PlanOptions holds the migration plan options to be used by PlanApplier.\n\tPlanOptions struct {\n\t\t// PlanWithSchemaQualifier allows setting a custom schema to prefix\n\t\t// tables and other resources. An empty string indicates no qualifier.\n\t\tSchemaQualifier *string\n\t\t// Indent is the string to use for indentation.\n\t\t// If empty, no indentation is used.\n\t\tIndent string\n\t\t// Mode represents the migration planning mode to be used. If not specified, the driver picks its default.\n\t\t// This is useful to indicate to the driver whether the context is a live database, an empty one, or the\n\t\t// versioned migration workflow.\n\t\tMode PlanMode\n\t}\n\n\t// PlanMode defines the plan mode to use.\n\tPlanMode uint8\n\n\t// PlanOption allows configuring a drivers' plan using functional arguments.\n\tPlanOption func(*PlanOptions)\n\n\t// StateReader wraps the method for reading a database/schema state.\n\t// The types below provides a few builtin options for reading a state\n\t// from a migration directory, a static object (e.g. a parsed file).\n\tStateReader interface {\n\t\tReadState(ctx context.Context) (*schema.Realm, error)\n\t}\n\n\t// The StateReaderFunc type is an adapter to allow the use of\n\t// ordinary functions as state readers.\n\tStateReaderFunc func(ctx context.Context) (*schema.Realm, error)\n)\n\n// ReadState calls f(ctx).\nfunc (f StateReaderFunc) ReadState(ctx context.Context) (*schema.Realm, error) {\n\treturn f(ctx)\n}\n\n// List of migration planning modes.\nconst (\n\tPlanModeUnset        PlanMode = iota // Driver default.\n\tPlanModeInPlace                      // Changes are applied in place (e.g. 'schema diff').\n\tPlanModeDeferred                     // Changes are planned for future applying (e.g. 'migrate diff').\n\tPlanModeDump                         // Schema creation dump (e.g. 'schema inspect').\n\tPlanModeUnsortedDump                 // Schema creation demo without sorting dependencies.\n)\n\n// Is reports whether m is match the given mode.\nfunc (m PlanMode) Is(m1 PlanMode) bool {\n\treturn m == m1 || m&m1 != 0\n}\n\n// ErrNoPlan is returned by Plan when there is no change between the two states.\nvar ErrNoPlan = errors.New(\"sql/migrate: no plan for matched states\")\n\n// Realm returns a StateReader for the static Realm object.\nfunc Realm(r *schema.Realm) StateReader {\n\treturn StateReaderFunc(func(context.Context) (*schema.Realm, error) {\n\t\treturn r, nil\n\t})\n}\n\n// Schema returns a StateReader for the static Schema object.\nfunc Schema(s *schema.Schema) StateReader {\n\treturn StateReaderFunc(func(context.Context) (*schema.Realm, error) {\n\t\tr := &schema.Realm{Schemas: []*schema.Schema{s}}\n\t\tif s.Realm != nil {\n\t\t\tr.Attrs = s.Realm.Attrs\n\t\t}\n\t\ts.Realm = r\n\t\treturn r, nil\n\t})\n}\n\n// RealmConn returns a StateReader for a Driver connected to a database.\nfunc RealmConn(drv Driver, opts *schema.InspectRealmOption) StateReader {\n\treturn StateReaderFunc(func(ctx context.Context) (*schema.Realm, error) {\n\t\treturn drv.InspectRealm(ctx, opts)\n\t})\n}\n\n// SchemaConn returns a StateReader for a Driver connected to a schema.\nfunc SchemaConn(drv Driver, name string, opts *schema.InspectOptions) StateReader {\n\treturn StateReaderFunc(func(ctx context.Context) (*schema.Realm, error) {\n\t\ts, err := drv.InspectSchema(ctx, name, opts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn Schema(s).ReadState(ctx)\n\t})\n}\n\ntype (\n\t// Planner can plan the steps to take to migrate from one state to another. It uses the enclosed Dir to\n\t// those changes to versioned migration files.\n\tPlanner struct {\n\t\tdrv      Driver              // driver to use\n\t\tdir      Dir                 // where migration files are stored and read from\n\t\tfmt      Formatter           // how to format a plan to migration files\n\t\tsum      bool                // whether to create a sum file for the migration directory\n\t\texclude  []string            // exclude resources from planning that match the patterns\n\t\tplanOpts []PlanOption        // plan options\n\t\tdiffOpts []schema.DiffOption // diff options\n\t}\n\n\t// PlannerOption allows managing a Planner using functional arguments.\n\tPlannerOption func(*Planner)\n\n\t// A RevisionReadWriter wraps the functionality for reading and writing migration revisions in a database table.\n\tRevisionReadWriter interface {\n\t\t// Ident returns an object identifies this history table.\n\t\tIdent() *TableIdent\n\t\t// ReadRevisions returns all revisions.\n\t\tReadRevisions(context.Context) ([]*Revision, error)\n\t\t// ReadRevision returns a revision by version.\n\t\t// Returns ErrRevisionNotExist if the version does not exist.\n\t\tReadRevision(context.Context, string) (*Revision, error)\n\t\t// WriteRevision saves the revision to the storage.\n\t\tWriteRevision(context.Context, *Revision) error\n\t\t// DeleteRevision deletes a revision by version from the storage.\n\t\tDeleteRevision(context.Context, string) error\n\t}\n\n\t// A Revision denotes an applied migration in a deployment. Used to track migration executions state of a database.\n\tRevision struct {\n\t\tVersion         string        `json:\"Version\"`             // Version of the migration.\n\t\tDescription     string        `json:\"Description\"`         // Description of this migration.\n\t\tType            RevisionType  `json:\"Type\"`                // Type of the migration.\n\t\tApplied         int           `json:\"Applied\"`             // Applied amount of statements in the migration.\n\t\tTotal           int           `json:\"Total\"`               // Total amount of statements in the migration.\n\t\tExecutedAt      time.Time     `json:\"ExecutedAt\"`          // ExecutedAt is the starting point of execution.\n\t\tExecutionTime   time.Duration `json:\"ExecutionTime\"`       // ExecutionTime of the migration.\n\t\tError           string        `json:\"Error,omitempty\"`     // Error of the migration, if any occurred.\n\t\tErrorStmt       string        `json:\"ErrorStmt,omitempty\"` // ErrorStmt is the statement that raised Error.\n\t\tHash            string        `json:\"-\"`                   // Hash of migration file.\n\t\tPartialHashes   []string      `json:\"-\"`                   // PartialHashes is the hashes of applied statements.\n\t\tOperatorVersion string        `json:\"OperatorVersion\"`     // OperatorVersion that executed this migration.\n\t}\n\n\t// RevisionType defines the type of the revision record in the history table.\n\tRevisionType uint\n\n\t// Executor is responsible to manage and execute a set of migration files against a database.\n\tExecutor struct {\n\t\tdrv         Driver             // The Driver to access and manage the database.\n\t\tdir         Dir                // The Dir with migration files to use.\n\t\trrw         RevisionReadWriter // The RevisionReadWriter to read and write database revisions to.\n\t\tlog         Logger             // The Logger to use.\n\t\torder       ExecOrder          // The order to execute the migration files.\n\t\tbaselineVer string             // Start the first migration after the given baseline version.\n\t\tallowDirty  bool               // Allow start working on a non-clean database.\n\t\toperator    string             // Revision.OperatorVersion\n\t}\n\n\t// ExecutorOption allows configuring an Executor using functional arguments.\n\tExecutorOption func(*Executor) error\n)\n\nconst (\n\t// RevisionTypeUnknown represents an unknown revision type.\n\t// This type is unexpected and exists here to only ensure\n\t// the type is not set to the zero value.\n\tRevisionTypeUnknown RevisionType = 0\n\n\t// RevisionTypeBaseline represents a baseline revision. Note that only\n\t// the first record can represent a baseline migration and most of its\n\t// fields are set to the zero value.\n\tRevisionTypeBaseline RevisionType = 1 << (iota - 1)\n\n\t// RevisionTypeExecute represents a migration that was executed.\n\tRevisionTypeExecute\n\n\t// RevisionTypeResolved represents a migration that was resolved. A migration\n\t// script that was script executed and then resolved should set its Type to\n\t// RevisionTypeExecute | RevisionTypeResolved.\n\tRevisionTypeResolved\n)\n\n// Has returns if the given flag is set.\nfunc (r RevisionType) Has(f RevisionType) bool {\n\treturn r&f != 0\n}\n\n// String implements fmt.Stringer.\nfunc (r RevisionType) String() string {\n\tswitch r {\n\tcase RevisionTypeBaseline:\n\t\treturn \"baseline\"\n\tcase RevisionTypeExecute:\n\t\treturn \"applied\"\n\tcase RevisionTypeResolved:\n\t\treturn \"manually set\"\n\tcase RevisionTypeExecute | RevisionTypeResolved:\n\t\treturn \"applied + manually set\"\n\tdefault:\n\t\treturn fmt.Sprintf(\"unknown (%04b)\", r)\n\t}\n}\n\n// MarshalText implements encoding.TextMarshaler.\nfunc (r RevisionType) MarshalText() ([]byte, error) {\n\treturn []byte(r.String()), nil\n}\n\n// NewPlanner creates a new Planner.\nfunc NewPlanner(drv Driver, dir Dir, opts ...PlannerOption) *Planner {\n\tp := &Planner{drv: drv, dir: dir, sum: true}\n\tfor _, opt := range opts {\n\t\topt(p)\n\t}\n\tif p.fmt == nil {\n\t\tp.fmt = DefaultFormatter\n\t}\n\treturn p\n}\n\n// PlanWithSchemaQualifier allows setting a custom schema to prefix tables and\n// other resources. An empty string indicates no prefix.\n//\n// Note, this options require the changes to be scoped to one\n// schema and returns an error otherwise.\nfunc PlanWithSchemaQualifier(q string) PlannerOption {\n\treturn func(p *Planner) {\n\t\tp.planOpts = append(p.planOpts, func(o *PlanOptions) {\n\t\t\to.SchemaQualifier = &q\n\t\t})\n\t}\n}\n\n// PlanWithIndent allows generating SQL statements with indentation.\n// An empty string indicates no indentation.\nfunc PlanWithIndent(indent string) PlannerOption {\n\treturn func(p *Planner) {\n\t\tp.planOpts = append(p.planOpts, func(o *PlanOptions) {\n\t\t\to.Indent = indent\n\t\t})\n\t}\n}\n\n// PlanWithMode allows setting a custom plan mode.\nfunc PlanWithMode(m PlanMode) PlannerOption {\n\treturn func(p *Planner) {\n\t\tp.planOpts = append(p.planOpts, func(o *PlanOptions) {\n\t\t\to.Mode = m\n\t\t})\n\t}\n}\n\n// PlanWithDiffOptions allows setting custom diff options.\nfunc PlanWithDiffOptions(opts ...schema.DiffOption) PlannerOption {\n\treturn func(p *Planner) {\n\t\tp.diffOpts = append(p.diffOpts, opts...)\n\t}\n}\n\n// PlanFormat sets the Formatter of a Planner.\nfunc PlanFormat(fmt Formatter) PlannerOption {\n\treturn func(p *Planner) {\n\t\tp.fmt = fmt\n\t}\n}\n\n// PlanWithChecksum allows setting if the hash-sum functionality\n// for the migration directory is enabled or not.\nfunc PlanWithChecksum(b bool) PlannerOption {\n\treturn func(p *Planner) {\n\t\tp.sum = b\n\t}\n}\n\n// PlanWithExclude allows setting exclude patterns for the planner.\n// Resources that match the patterns are excluded from planning.\nfunc PlanWithExclude(patterns ...string) PlannerOption {\n\treturn func(p *Planner) {\n\t\tp.exclude = patterns\n\t}\n}\n\nvar (\n\t// WithFormatter calls PlanFormat.\n\t// Deprecated: use PlanFormat instead.\n\tWithFormatter = PlanFormat\n\t// DisableChecksum calls PlanWithChecksum(false).\n\t// Deprecated: use PlanWithoutChecksum instead.\n\tDisableChecksum = func() PlannerOption { return PlanWithChecksum(false) }\n)\n\n// Plan calculates the migration Plan required for moving the current state (from) state to\n// the next state (to). A StateReader can be a directory, static schema elements or a Driver connection.\nfunc (p *Planner) Plan(ctx context.Context, name string, to StateReader) (*Plan, error) {\n\treturn p.plan(ctx, name, to, true)\n}\n\n// PlanSchema is like Plan but limits its scope to the schema connection.\n// Note, the operation fails in case the connection was not set to a schema.\nfunc (p *Planner) PlanSchema(ctx context.Context, name string, to StateReader) (*Plan, error) {\n\treturn p.plan(ctx, name, to, false)\n}\n\nfunc (p *Planner) plan(ctx context.Context, name string, to StateReader, realmScope bool) (*Plan, error) {\n\tcurrent, err := p.current(ctx, realmScope)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdesired, err := to.ReadState(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar changes []schema.Change\n\tswitch {\n\tcase realmScope:\n\t\tchanges, err = p.drv.RealmDiff(current, desired, p.diffOpts...)\n\tdefault:\n\t\tswitch n, m := len(current.Schemas), len(desired.Schemas); {\n\t\tcase n == 0:\n\t\t\treturn nil, errors.New(\"no schema was found in current state after replaying migration directory\")\n\t\tcase n > 1:\n\t\t\treturn nil, fmt.Errorf(\"%d schemas were found in current state after replaying migration directory\", len(current.Schemas))\n\t\tcase m == 0:\n\t\t\treturn nil, errors.New(\"no schema was found in desired state\")\n\t\tcase m > 1:\n\t\t\treturn nil, fmt.Errorf(\"%d schemas were found in desired state; expect 1\", len(desired.Schemas))\n\t\tdefault:\n\t\t\ts1, s2 := *current.Schemas[0], *desired.Schemas[0]\n\t\t\t// Avoid comparing schema names when scope is limited to one schema,\n\t\t\t// and the schema qualifier is controlled by the caller.\n\t\t\tif s1.Name != s2.Name {\n\t\t\t\ts1.Name = s2.Name\n\t\t\t}\n\t\t\tchanges, err = p.drv.SchemaDiff(&s1, &s2, p.diffOpts...)\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(changes) == 0 {\n\t\treturn nil, ErrNoPlan\n\t}\n\treturn p.drv.PlanChanges(ctx, name, changes, p.planOpts...)\n}\n\n// Checkpoint calculate the current state of the migration directory by executing its files,\n// and return a migration (checkpoint) Plan that represents its states.\nfunc (p *Planner) Checkpoint(ctx context.Context, name string) (*Plan, error) {\n\treturn p.checkpoint(ctx, name, true)\n}\n\n// CheckpointSchema is like Checkpoint but limits its scope to the schema connection.\n// Note, the operation fails in case the connection was not set to a schema.\nfunc (p *Planner) CheckpointSchema(ctx context.Context, name string) (*Plan, error) {\n\treturn p.checkpoint(ctx, name, false)\n}\n\nfunc (p *Planner) checkpoint(ctx context.Context, name string, realmScope bool) (*Plan, error) {\n\tcurrent, err := p.current(ctx, realmScope)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar changes []schema.Change\n\tswitch {\n\tcase realmScope:\n\t\tchanges, err = p.drv.RealmDiff(schema.NewRealm(), current, p.diffOpts...)\n\tdefault:\n\t\tswitch n := len(current.Schemas); {\n\t\tcase n == 0:\n\t\t\treturn nil, errors.New(\"no schema was found in current state after replaying migration directory\")\n\t\tcase n > 1:\n\t\t\treturn nil, fmt.Errorf(\"%d schemas were found in current state after replaying migration directory\", len(current.Schemas))\n\t\tdefault:\n\t\t\ts1 := current.Schemas[0]\n\t\t\ts2 := schema.New(s1.Name).AddAttrs(s1.Attrs...)\n\t\t\tchanges, err = p.drv.SchemaDiff(s2, s1, p.diffOpts...)\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// No changes mean an empty checkpoint.\n\tif len(changes) == 0 {\n\t\treturn &Plan{Name: name}, nil\n\t}\n\treturn p.drv.PlanChanges(ctx, name, changes, p.planOpts...)\n}\n\n// current returns the current realm state.\nfunc (p *Planner) current(ctx context.Context, realmScope bool) (*schema.Realm, error) {\n\tfrom, err := NewExecutor(p.drv, p.dir, NopRevisionReadWriter{})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn from.Replay(ctx, func() StateReader {\n\t\tif realmScope {\n\t\t\treturn RealmConn(p.drv, &schema.InspectRealmOption{\n\t\t\t\tExclude: p.exclude,\n\t\t\t})\n\t\t}\n\t\t// In case the scope is the schema connection,\n\t\t// inspect it and return its connected realm.\n\t\treturn SchemaConn(p.drv, \"\", &schema.InspectOptions{\n\t\t\tExclude: p.exclude,\n\t\t})\n\t}())\n}\n\n// WritePlan writes the given Plan to the Dir based on the configured Formatter.\nfunc (p *Planner) WritePlan(plan *Plan) error {\n\t// Format the plan into files.\n\tfiles, err := p.fmt.Format(plan)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Store the files in the migration directory.\n\tfor _, f := range files {\n\t\tif err := p.dir.WriteFile(f.Name(), f.Bytes()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn p.writeSum()\n}\n\n// WriteCheckpoint writes the given Plan as a checkpoint file to the Dir based on the configured Formatter.\nfunc (p *Planner) WriteCheckpoint(plan *Plan, tag string) error {\n\tck, ok := p.dir.(CheckpointDir)\n\tif !ok {\n\t\treturn fmt.Errorf(\"checkpoint is not supported by %T\", p.dir)\n\t}\n\t// Format the plan into files.\n\tfiles, err := p.fmt.Format(plan)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(files) != 1 {\n\t\treturn fmt.Errorf(\"expected one checkpoint file, got %d\", len(files))\n\t}\n\tif err := ck.WriteCheckpoint(files[0].Name(), tag, files[0].Bytes()); err != nil {\n\t\treturn err\n\t}\n\treturn p.writeSum()\n}\n\n// writeSum writes the sum file to the Dir, if enabled.\nfunc (p *Planner) writeSum() error {\n\tif !p.sum {\n\t\treturn nil\n\t}\n\tsum, err := p.dir.Checksum()\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn WriteSumFile(p.dir, sum)\n}\n\nvar (\n\t// ErrNoPendingFiles is returned if there are no pending migration files to execute on the managed database.\n\tErrNoPendingFiles = errors.New(\"sql/migrate: no pending migration files\")\n\t// ErrRevisionNotExist is returned if the requested revision is not found in the storage.\n\tErrRevisionNotExist = errors.New(\"sql/migrate: revision not found\")\n)\n\n// MissingMigrationError is returned if a revision is partially applied but\n// the matching migration file is not found in the migration directory.\ntype MissingMigrationError struct{ Version, Description string }\n\n// Error implements error.\nfunc (e MissingMigrationError) Error() string {\n\treturn fmt.Sprintf(\n\t\t\"sql/migrate: missing migration: revision %q is partially applied but migration file was not found\",\n\t\tfmt.Sprintf(\"%s_%s.sql\", e.Version, e.Description),\n\t)\n}\n\n// NewExecutor creates a new Executor with default values.\nfunc NewExecutor(drv Driver, dir Dir, rrw RevisionReadWriter, opts ...ExecutorOption) (*Executor, error) {\n\tif drv == nil {\n\t\treturn nil, errors.New(\"sql/migrate: no driver given\")\n\t}\n\tif dir == nil {\n\t\treturn nil, errors.New(\"sql/migrate: no dir given\")\n\t}\n\tif rrw == nil {\n\t\treturn nil, errors.New(\"sql/migrate: no revision storage given\")\n\t}\n\tex := &Executor{drv: drv, dir: dir, rrw: rrw}\n\tfor _, opt := range opts {\n\t\tif err := opt(ex); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif ex.log == nil {\n\t\tex.log = NopLogger{}\n\t}\n\tif ex.baselineVer != \"\" && ex.allowDirty {\n\t\treturn nil, errors.New(\"sql/migrate: baseline and allow-dirty are mutually exclusive\")\n\t}\n\treturn ex, nil\n}\n\n// WithAllowDirty defines if we can start working on a non-clean database\n// in the first migration execution.\nfunc WithAllowDirty(b bool) ExecutorOption {\n\treturn func(ex *Executor) error {\n\t\tex.allowDirty = b\n\t\treturn nil\n\t}\n}\n\n// WithBaselineVersion allows setting the baseline version of the database on the\n// first migration. Hence, all versions up to and including this version are skipped.\nfunc WithBaselineVersion(v string) ExecutorOption {\n\treturn func(ex *Executor) error {\n\t\tex.baselineVer = v\n\t\treturn nil\n\t}\n}\n\n// WithLogger sets the Logger of an Executor.\nfunc WithLogger(log Logger) ExecutorOption {\n\treturn func(ex *Executor) error {\n\t\tex.log = log\n\t\treturn nil\n\t}\n}\n\n// ExecOrder defines the execution order to use.\ntype ExecOrder uint\n\nconst (\n\t// ExecOrderLinear is the default execution order mode.\n\t// It expects a linear history and fails if it encounters files that were\n\t// added out of order. For example, a new file was added with version lower\n\t// than the last applied revision.\n\tExecOrderLinear ExecOrder = iota\n\n\t// ExecOrderLinearSkip is a softer version of ExecOrderLinear.\n\t// This means that if a new file is added with a version lower than the last\n\t// applied revision, it will be skipped.\n\tExecOrderLinearSkip\n\n\t// ExecOrderNonLinear executes migration files that were added out of order.\n\tExecOrderNonLinear\n)\n\n// WithExecOrder sets the execution order to use.\nfunc WithExecOrder(o ExecOrder) ExecutorOption {\n\treturn func(ex *Executor) error {\n\t\tex.order = o\n\t\treturn nil\n\t}\n}\n\n// WithOperatorVersion sets the operator version to save on the revisions\n// when executing migration files.\nfunc WithOperatorVersion(v string) ExecutorOption {\n\treturn func(ex *Executor) error {\n\t\tex.operator = v\n\t\treturn nil\n\t}\n}\n\n// Pending returns all pending (not fully applied) migration files in the migration directory.\nfunc (e *Executor) Pending(ctx context.Context) ([]File, error) {\n\t// Don't operate with a broken migration directory.\n\tif err := e.ValidateDir(ctx); err != nil {\n\t\treturn nil, err\n\t}\n\t// Read all applied database revisions.\n\trevs, err := e.rrw.ReadRevisions(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/migrate: read revisions: %w\", err)\n\t}\n\tall, err := e.dir.Files()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/migrate: read migration directory files: %w\", err)\n\t}\n\tmigrations := SkipCheckpointFiles(all)\n\tvar pending []File\n\tswitch {\n\t// If it is the first time we run.\n\tcase len(revs) == 0:\n\t\tvar cerr *NotCleanError\n\t\tif err = e.drv.CheckClean(ctx, e.rrw.Ident()); err != nil && !errors.As(err, &cerr) {\n\t\t\treturn nil, err\n\t\t}\n\t\t// In case the workspace is not clean one of the flags is required.\n\t\tif cerr != nil && !e.allowDirty && e.baselineVer == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"%w. baseline version or allow-dirty is required\", cerr)\n\t\t}\n\t\tif e.baselineVer != \"\" {\n\t\t\tbaseline := FilesLastIndex(migrations, func(f File) bool {\n\t\t\t\treturn f.Version() == e.baselineVer\n\t\t\t})\n\t\t\tif baseline == -1 {\n\t\t\t\treturn nil, fmt.Errorf(\"baseline version %q not found\", e.baselineVer)\n\t\t\t}\n\t\t\tf := migrations[baseline]\n\t\t\t// Write the first revision in the database as a baseline revision.\n\t\t\tif err := e.writeRevision(ctx, &Revision{Version: f.Version(), Description: f.Desc(), Type: RevisionTypeBaseline}); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tpending = migrations[baseline+1:]\n\t\t\t// In case the \"allow-dirty\" option was set, or the database is clean,\n\t\t\t// the starting-point is the first migration file or the last checkpoint.\n\t\t} else if pending, err = FilesFromLastCheckpoint(e.dir); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t// In case we applied a checkpoint, but it was only partially applied.\n\tcase revs[len(revs)-1].Applied != revs[len(revs)-1].Total && len(all) > 0:\n\t\tif idx, found := slices.BinarySearchFunc(all, revs[len(revs)-1], func(f File, r *Revision) int {\n\t\t\treturn strings.Compare(f.Version(), r.Version)\n\t\t}); found {\n\t\t\tif f, ok := all[idx].(CheckpointFile); ok && f.IsCheckpoint() {\n\t\t\t\t// There can only be one checkpoint file and it must be the first one applied.\n\t\t\t\t// Thus, we can consider all migrations following the checkpoint to be pending.\n\t\t\t\treturn append([]File{f}, SkipCheckpointFiles(all[idx:])...), nil\n\t\t\t}\n\t\t}\n\t\tif len(migrations) == 0 {\n\t\t\tbreak // don't fall through the next case if there are no migrations\n\t\t}\n\t\tfallthrough // proceed normally\n\t// In case we applied/marked revisions in the past, and there is work to do.\n\tcase len(migrations) > 0:\n\t\tvar (\n\t\t\tlast      = revs[len(revs)-1]\n\t\t\tpartially = last.Applied != last.Total\n\t\t\tfn        = func(f File) bool { return f.Version() <= last.Version }\n\t\t)\n\t\tif partially {\n\t\t\t// If the last file is partially applied, we need to find the matching migration file in order to\n\t\t\t// continue execution at the correct statement.\n\t\t\tfn = func(f File) bool { return f.Version() == last.Version }\n\t\t}\n\t\t// Consider all migration files having a version < the latest revision version as pending. If the\n\t\t// last revision is partially applied, it is considered pending as well.\n\t\tidx := FilesLastIndex(migrations, fn)\n\t\tif idx == -1 {\n\t\t\t// If we cannot find the matching migration version for a partially applied migration,\n\t\t\t// error out since we cannot determine how to proceed from here.\n\t\t\tif partially {\n\t\t\t\treturn nil, &MissingMigrationError{last.Version, last.Description}\n\t\t\t}\n\t\t\t// All migrations have a higher version than the latest revision. Take every migration file as pending.\n\t\t\treturn migrations, nil\n\t\t}\n\t\t// If this file was not partially applied, take the next one.\n\t\tif last.Applied == last.Total {\n\t\t\tidx++\n\t\t}\n\t\tpending = migrations[idx:]\n\t\t// Capture all files (versions) between first and last revisions and ensure they\n\t\t// were actually applied. Then, error or execute according to the execution order.\n\t\t// Note, \"first\" is computed as it can be set to the first checkpoint, which may\n\t\t// not be the first migration file.\n\t\tif first := slices.IndexFunc(migrations[:idx], func(f File) bool {\n\t\t\treturn f.Version() >= revs[0].Version\n\t\t}); first != -1 && first < idx && e.order != ExecOrderLinearSkip {\n\t\t\tvar skipped []File\n\t\t\tfor _, f := range migrations[first:idx] {\n\t\t\t\tif _, found := slices.BinarySearchFunc(revs, f, func(r *Revision, f File) int {\n\t\t\t\t\treturn strings.Compare(r.Version, f.Version())\n\t\t\t\t}); !found {\n\t\t\t\t\tskipped = append(skipped, f)\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch {\n\t\t\tcase len(skipped) == 0:\n\t\t\tcase e.order == ExecOrderNonLinear:\n\t\t\t\tpending = append(skipped, pending...)\n\t\t\tcase e.order == ExecOrderLinear:\n\t\t\t\treturn nil, &HistoryNonLinearError{OutOfOrder: skipped, Pending: pending}\n\t\t\t}\n\t\t}\n\t}\n\tif len(pending) == 0 {\n\t\treturn nil, ErrNoPendingFiles\n\t}\n\treturn pending, nil\n}\n\n// Execute executes the given migration file on the database. If it sees a file, that has been partially applied, it\n// will continue with the next statement in line.\nfunc (e *Executor) Execute(ctx context.Context, m File) (err error) {\n\thf, err := e.dir.Checksum()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"sql/migrate: compute hash: %w\", err)\n\t}\n\thash, err := hf.SumByName(m.Name())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"sql/migrate: scanning checksum from %q: %w\", m.Name(), err)\n\t}\n\tstmts, err := e.fileStmts(m)\n\tif err != nil {\n\t\terr = fmt.Errorf(\"sql/migrate: scanning statements from %q: %w\", m.Name(), err)\n\t\te.log.Log(LogError{Error: err})\n\t\treturn err\n\t}\n\t// Create checksums for the statements.\n\tvar (\n\t\tsums = make([]string, len(stmts))\n\t\th    = sha256.New()\n\t)\n\tfor i, stmt := range stmts {\n\t\tif _, err := h.Write([]byte(stmt.Text)); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tsums[i] = base64.StdEncoding.EncodeToString(h.Sum(nil))\n\t}\n\tversion := m.Version()\n\t// If there already is a revision with this version in the database,\n\t// and it is partially applied, continue where the last attempt was left off.\n\tr, err := e.rrw.ReadRevision(ctx, version)\n\tif err != nil && !errors.Is(err, ErrRevisionNotExist) {\n\t\treturn fmt.Errorf(\"sql/migrate: read revision: %w\", err)\n\t}\n\tif errors.Is(err, ErrRevisionNotExist) {\n\t\t// Haven't seen this file before, create a new revision.\n\t\tr = &Revision{\n\t\t\tVersion:     version,\n\t\t\tDescription: m.Desc(),\n\t\t\tType:        RevisionTypeExecute,\n\t\t\tTotal:       len(stmts),\n\t\t\tHash:        hash,\n\t\t}\n\t}\n\t// Save once to mark as started in the database.\n\tif err = e.writeRevision(ctx, r); err != nil {\n\t\te.log.Log(LogError{Error: err})\n\t\treturn err\n\t}\n\t// Make sure to store the Revision information, if it did not fail before.\n\tdefer func(ctx context.Context, e *Executor, r *Revision) {\n\t\tif !errors.As(err, new(*WriteRevisionError)) {\n\t\t\tif err2 := e.writeRevision(ctx, r); err2 != nil {\n\t\t\t\terr = errors.Join(err, err2)\n\t\t\t}\n\t\t}\n\t}(ctx, e, r)\n\tif r.Applied > 0 {\n\t\t// If the file has been applied partially before, check if the\n\t\t// applied statements have not changed.\n\t\tfor i := 0; i < r.Applied; i++ {\n\t\t\tif i > len(sums) || sums[i] != strings.TrimPrefix(r.PartialHashes[i], \"h1:\") {\n\t\t\t\terr = HistoryChangedError{m.Name(), i + 1}\n\t\t\t\te.log.Log(LogError{Error: err})\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\te.log.Log(LogFile{m, r.Version, r.Description, r.Applied})\n\tif err := e.fileChecks(ctx, m, r); err != nil {\n\t\te.log.Log(LogError{Error: err})\n\t\tr.done()\n\t\tr.Error = err.Error()\n\t\treturn err\n\t}\n\tfor _, stmt := range stmts[r.Applied:] {\n\t\te.log.Log(LogStmt{SQL: stmt.Text, Stmt: stmt})\n\t\tif _, err = e.drv.ExecContext(ctx, stmt.Text); err != nil {\n\t\t\te.log.Log(LogError{SQL: stmt.Text, Stmt: stmt, Error: err})\n\t\t\tr.done()\n\t\t\tr.ErrorStmt = stmt.Text\n\t\t\tr.Error = err.Error()\n\t\t\treturn &StmtExecError{File: m, Stmt: stmt, Version: r.Version, Err: err}\n\t\t}\n\t\tr.PartialHashes = append(r.PartialHashes, \"h1:\"+sums[r.Applied])\n\t\tr.Applied++\n\t\t// In case retry attempts succeeded,\n\t\t// clean up the error from the table.\n\t\tif r.Error != \"\" {\n\t\t\tr.Error = \"\"\n\t\t\tr.ErrorStmt = \"\"\n\t\t}\n\t\tif err = e.writeRevision(ctx, r); err != nil {\n\t\t\te.log.Log(LogError{Error: err})\n\t\t\treturn err\n\t\t}\n\t}\n\t// In case the file was applied successfully, clean out the partial revisions.\n\tr.PartialHashes = nil\n\tr.done()\n\treturn\n}\n\nfunc (e *Executor) writeRevision(ctx context.Context, r *Revision) error {\n\tr.ExecutedAt = time.Now()\n\tr.OperatorVersion = e.operator\n\tif err := e.rrw.WriteRevision(ctx, r); err != nil {\n\t\treturn &WriteRevisionError{Err: err, Revision: r}\n\t}\n\treturn nil\n}\n\n// WriteRevisionError is reported when writing a\n// revision to the RevisionReadWriter fails.\ntype WriteRevisionError struct {\n\tErr      error\n\tRevision *Revision\n}\n\nfunc (e WriteRevisionError) Error() string {\n\treturn \"sql/migrate: write revision: \" + e.Err.Error()\n}\n\nfunc (e WriteRevisionError) Unwrap() error {\n\treturn e.Err\n}\n\n// HistoryChangedError is returned if between two execution attempts already applied statements of a file have changed.\ntype HistoryChangedError struct {\n\tFile string\n\tStmt int\n}\n\nfunc (e HistoryChangedError) Error() string {\n\treturn fmt.Sprintf(\"sql/migrate: history changed: statement %d from file %q changed\", e.Stmt, e.File)\n}\n\n// HistoryNonLinearError is returned if the migration history is not linear. Means, a file was added out of order.\n// The executor can be configured to ignore this error and continue execution. See WithExecOrder for details.\ntype HistoryNonLinearError struct {\n\t// OutOfOrder are the files that were added out of order.\n\tOutOfOrder []File\n\t// Pending are valid files that are still pending for execution.\n\tPending []File\n}\n\nfunc (e HistoryNonLinearError) Error() string {\n\tnames := make([]string, len(e.OutOfOrder))\n\tfor i := range e.OutOfOrder {\n\t\tnames[i] = e.OutOfOrder[i].Name()\n\t}\n\tf := fmt.Sprintf(\"files %s were\", strings.Join(names, \", \"))\n\tif len(e.OutOfOrder) == 1 {\n\t\tf = fmt.Sprintf(\"file %s was\", names[0])\n\t}\n\treturn fmt.Sprintf(\"migration %s added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error\", f)\n}\n\n// ExecuteN executes n pending migration files. If n<=0 all pending migration files are executed.\nfunc (e *Executor) ExecuteN(ctx context.Context, n int) (err error) {\n\tpending, err := e.Pending(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif n > 0 {\n\t\tif n >= len(pending) {\n\t\t\tn = len(pending)\n\t\t}\n\t\tpending = pending[:n]\n\t}\n\treturn e.exec(ctx, pending)\n}\n\n// ExecuteTo executes all pending migration files up to and including version.\nfunc (e *Executor) ExecuteTo(ctx context.Context, version string) (err error) {\n\tfiles, err := e.dir.Files()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"sql/migrate: read migration directory files: %w\", err)\n\t}\n\tidx := FilesLastIndex(files, func(f File) bool {\n\t\treturn f.Version() == version\n\t})\n\tif idx == -1 {\n\t\tm := fmt.Sprintf(\"sql/migrate: migration with version %q not found\", version)\n\t\tif idx = FilesLastIndex(files, func(f File) bool {\n\t\t\tv := f.Version()\n\t\t\treturn strings.Contains(version, v) || (strings.Contains(v, version) && len(v)-len(version) > 1)\n\t\t}); version != \"\" && idx != -1 {\n\t\t\tm += fmt.Sprintf(\". Did you mean %q?\", files[idx].Version())\n\t\t}\n\t\treturn errors.New(m)\n\t}\n\tvar pending []File\n\tswitch beforeCk := slices.ContainsFunc(files[idx+1:], func(f File) bool {\n\t\tc, ok := f.(CheckpointFile)\n\t\treturn ok && c.IsCheckpoint()\n\t}); {\n\t// If the version we want to migrate to is before a\n\t// checkpoint, it will be skipped by Pending.\n\tcase beforeCk:\n\t\tdir, mem := e.dir, &MemDir{}\n\t\tif err := mem.CopyFiles(files[:idx+1]); err != nil {\n\t\t\treturn fmt.Errorf(\"sql/migrate: copy files to memory: %w\", err)\n\t\t}\n\t\te.dir = mem\n\t\tpending, err = e.Pending(ctx)\n\t\te.dir = dir\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\tdefault:\n\t\tif pending, err = e.Pending(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Strip pending files greater given version.\n\t\tswitch idx := FilesLastIndex(pending, func(file File) bool {\n\t\t\treturn file.Version() == version\n\t\t}); idx {\n\t\tcase -1:\n\t\t\treturn fmt.Errorf(\"sql/migrate: migration with version %q not found\", version)\n\t\tdefault:\n\t\t\tpending = pending[:idx+1]\n\t\t}\n\t}\n\treturn e.exec(ctx, pending)\n}\n\n// ExecuteFiles executes the given migration files on the database. Note, this method does not\n// validate the migration directory, check for pending/baseline/checkpoint files, or update the\n// revision history. It is meant to be used by the declarative workflow to apply files as-is.\nfunc (e *Executor) ExecuteFiles(ctx context.Context, files []File) error {\n\tswitch e.rrw.(type) {\n\tcase NopRevisionReadWriter, *NopRevisionReadWriter:\n\t\treturn e.exec(ctx, files)\n\tdefault:\n\t\treturn fmt.Errorf(\"sql/migrate: unexpected usage of ExecuteFiles with non-nop revision read writer: %T\", e.rrw)\n\t}\n}\n\nfunc (e *Executor) exec(ctx context.Context, files []File) error {\n\trevs, err := e.rrw.ReadRevisions(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"sql/migrate: read revisions: %w\", err)\n\t}\n\tLogIntro(e.log, revs, files)\n\tfor _, m := range files {\n\t\tif err := e.Execute(ctx, m); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\te.log.Log(LogDone{})\n\treturn err\n}\n\ntype (\n\treplayConfig struct {\n\t\tversion string // to which version to replay (inclusive)\n\t}\n\t// ReplayOption configures a migration directory replay behavior.\n\tReplayOption func(*replayConfig)\n)\n\n// ReplayToVersion configures the last version to apply when replaying the migration directory.\nfunc ReplayToVersion(v string) ReplayOption {\n\treturn func(c *replayConfig) {\n\t\tc.version = v\n\t}\n}\n\n// Replay the migration directory and invoke the state to get back the inspection result.\nfunc (e *Executor) Replay(ctx context.Context, r StateReader, opts ...ReplayOption) (_ *schema.Realm, err error) {\n\tc := &replayConfig{}\n\tfor _, opt := range opts {\n\t\topt(c)\n\t}\n\t// Clean up after ourselves.\n\trestore, err := e.drv.Snapshot(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/migrate: taking database snapshot: %w\", err)\n\t}\n\tdefer func() {\n\t\tif err2 := restore(ctx); err2 != nil {\n\t\t\terr = errors.Join(err, err2)\n\t\t}\n\t}()\n\t// Replay the migration directory on the database.\n\tswitch {\n\tcase c.version != \"\":\n\t\terr = e.ExecuteTo(ctx, c.version)\n\tdefault:\n\t\terr = e.ExecuteN(ctx, 0)\n\t}\n\tif err != nil && !errors.Is(err, ErrNoPendingFiles) {\n\t\treturn nil, fmt.Errorf(\"sql/migrate: read migration directory state: %w\", err)\n\t}\n\treturn r.ReadState(ctx)\n}\n\ntype (\n\t// Snapshoter wraps the Snapshot method.\n\tSnapshoter interface {\n\t\t// Snapshot takes a snapshot of the current database state and returns a function that can be called to restore\n\t\t// that state. Snapshot should return an error, if the current state can not be restored completely, e.g. if\n\t\t// there is a table already containing some rows.\n\t\tSnapshot(context.Context) (RestoreFunc, error)\n\t}\n\n\t// RestoreFunc is returned by the Snapshoter to explicitly restore the database state.\n\tRestoreFunc func(context.Context) error\n\n\t// TableIdent describes a table identifier returned by the revisions table.\n\tTableIdent struct {\n\t\tName   string // name of the table.\n\t\tSchema string // optional schema.\n\t}\n\n\t// CleanChecker wraps the single CheckClean method.\n\tCleanChecker interface {\n\t\t// CheckClean checks if the connected realm or schema does not contain any resources besides the\n\t\t// revision history table. A NotCleanError is returned in case the connection is not-empty.\n\t\tCheckClean(context.Context, *TableIdent) error\n\t}\n\n\t// NotCleanError is returned when the connected dev-db is not in a clean state (aka it has schemas and tables).\n\t// This check is done to ensure no data is lost by overriding it when working on the dev-db.\n\tNotCleanError struct {\n\t\tReason string        // reason why the database is considered not clean\n\t\tState  *schema.Realm // the state the dev-connection is in\n\t}\n\n\t// StmtExecError is returned when the execution of a statement fails during migration.\n\tStmtExecError struct {\n\t\tFile    File   // Migration file that failed.\n\t\tStmt    *Stmt  // Statement that failed.\n\t\tVersion string // Version of the file.\n\t\tErr     error  // Underlying error during execution.\n\t}\n)\n\nfunc (e *StmtExecError) Unwrap() error {\n\treturn e.Err\n}\n\nfunc (e *NotCleanError) Error() string {\n\treturn \"sql/migrate: connected database is not clean: \" + e.Reason\n}\n\n// NopRevisionReadWriter is a RevisionReadWriter that does nothing.\n// It is useful for one-time replay of the migration directory.\ntype NopRevisionReadWriter struct{}\n\n// Ident implements RevisionsReadWriter.TableIdent.\nfunc (NopRevisionReadWriter) Ident() *TableIdent {\n\treturn nil\n}\n\n// ReadRevisions implements RevisionsReadWriter.ReadRevisions.\nfunc (NopRevisionReadWriter) ReadRevisions(context.Context) ([]*Revision, error) {\n\treturn nil, nil\n}\n\n// ReadRevision implements RevisionsReadWriter.ReadRevision.\nfunc (NopRevisionReadWriter) ReadRevision(context.Context, string) (*Revision, error) {\n\treturn nil, ErrRevisionNotExist\n}\n\n// WriteRevision implements RevisionsReadWriter.WriteRevision.\nfunc (NopRevisionReadWriter) WriteRevision(context.Context, *Revision) error {\n\treturn nil\n}\n\n// DeleteRevision implements RevisionsReadWriter.DeleteRevision.\nfunc (NopRevisionReadWriter) DeleteRevision(context.Context, string) error {\n\treturn nil\n}\n\nvar _ RevisionReadWriter = (*NopRevisionReadWriter)(nil)\n\n// done computes and sets the ExecutionTime.\nfunc (r *Revision) done() {\n\tr.ExecutionTime = time.Now().Sub(r.ExecutedAt)\n}\n\ntype (\n\t// A Logger logs migration execution.\n\tLogger interface {\n\t\tLog(LogEntry)\n\t}\n\n\t// LogEntry marks several types of logs to be passed to a Logger.\n\tLogEntry interface {\n\t\tlogEntry()\n\t}\n\n\t// LogExecution is sent once when execution of multiple migration files has been started.\n\t// It holds the filenames of the pending migration files.\n\tLogExecution struct {\n\t\t// From what version.\n\t\tFrom string\n\t\t// To what version.\n\t\tTo string\n\t\t// Migration Files to be executed.\n\t\tFiles []File\n\t}\n\n\t// LogFile is sent if a new migration file is executed.\n\tLogFile struct {\n\t\t// The File being executed.\n\t\tFile File\n\t\t// Version executed.\n\t\t// Deprecated: Use File.Version() instead.\n\t\tVersion string\n\t\t// Desc of migration executed.\n\t\t// Deprecated: Use File.Desc() instead.\n\t\tDesc string\n\t\t// Skip holds the number of stmts of this file that will be skipped.\n\t\t// This happens, if a migration file was only applied partially and will now continue to be applied.\n\t\tSkip int\n\t}\n\n\t// LogStmt is sent if a new SQL statement is executed.\n\tLogStmt struct {\n\t\tSQL  string // SQL statement.\n\t\tStmt *Stmt  // Scanned statement with extra information.\n\t}\n\n\t// LogDone is sent if the execution is done.\n\tLogDone struct{}\n\n\t// LogError is sent if there is an error while execution.\n\tLogError struct {\n\t\tSQL   string // Set, if Error was caused by a SQL statement.\n\t\tStmt  *Stmt  // Underlying statement declaration.\n\t\tError error\n\t}\n\n\t// LogChecks is sent before the execution of a group of check statements.\n\tLogChecks struct {\n\t\tName  string   // Optional name.\n\t\tStmts []string // Check statements.\n\t}\n\n\t// LogCheck is sent after a specific check statement was executed.\n\tLogCheck struct {\n\t\tStmt  string // Check statement.\n\t\tError error  // Check error.\n\t\tDecl  *Stmt  // Check statement declaration.\n\t}\n\n\t// LogChecksDone is sent after the execution of a group of checks\n\t// together with some text message and error if the group failed.\n\tLogChecksDone struct {\n\t\tError error // Optional error.\n\t}\n\n\t// NopLogger is a Logger that does nothing.\n\t// It is useful for one-time replay of the migration directory.\n\tNopLogger struct{}\n)\n\nfunc (LogExecution) logEntry()  {}\nfunc (LogFile) logEntry()       {}\nfunc (LogStmt) logEntry()       {}\nfunc (LogCheck) logEntry()      {}\nfunc (LogChecks) logEntry()     {}\nfunc (LogChecksDone) logEntry() {}\nfunc (LogDone) logEntry()       {}\nfunc (LogError) logEntry()      {}\n\n// Log implements the Logger interface.\nfunc (NopLogger) Log(LogEntry) {}\n\n// LogIntro gathers some meta information from the migration files and stored\n// revisions to log some general information prior to actual execution.\nfunc LogIntro(l Logger, revs []*Revision, files []File) {\n\te := LogExecution{Files: files}\n\tif len(revs) > 0 {\n\t\te.From = revs[len(revs)-1].Version\n\t}\n\tif len(files) > 0 {\n\t\te.To = files[len(files)-1].Version()\n\t}\n\tl.Log(e)\n}\n\n// LogNoPendingFiles starts a new LogExecution and LogDone\n// to indicate that there are no pending files to be executed.\nfunc LogNoPendingFiles(l Logger, revs []*Revision) {\n\tLogIntro(l, revs, nil)\n\tl.Log(LogDone{})\n}\n"
  },
  {
    "path": "sql/migrate/migrate_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage migrate\n\nimport (\n\t\"context\"\n\t\"fmt\"\n)\n\n// IsCheckpoint reports whether the file is a checkpoint file.\nfunc (f *LocalFile) IsCheckpoint() bool {\n\treturn f.isCheckpoint()\n}\n\n// CheckpointTag returns the tag of the checkpoint file, if defined.\nfunc (f *LocalFile) CheckpointTag() (string, error) {\n\treturn f.checkpointTag()\n}\n\n// fileStmts returns the statements defined in the given file.\nfunc (e *Executor) fileStmts(f File) ([]*Stmt, error) {\n\treturn FileStmtDecls(e.drv, f)\n}\n\nfunc (e *Executor) fileChecks(context.Context, File, *Revision) error {\n\treturn nil // unimplemented\n}\n\n// ValidateDir before operating on it.\nfunc (e *Executor) ValidateDir(context.Context) error {\n\tif err := Validate(e.dir); err != nil {\n\t\treturn fmt.Errorf(\"sql/migrate: validate migration directory: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (e *StmtExecError) Error() string {\n\treturn fmt.Sprintf(\"sql/migrate: executing statement %q from version %q: %v\", e.Stmt.Text, e.Version, e.Err)\n}\n"
  },
  {
    "path": "sql/migrate/migrate_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage migrate_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRevisionType_MarshalText(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tr  migrate.RevisionType\n\t\tex string\n\t}{\n\t\t{migrate.RevisionTypeUnknown, \"unknown (0000)\"},\n\t\t{migrate.RevisionTypeBaseline, \"baseline\"},\n\t\t{migrate.RevisionTypeExecute, \"applied\"},\n\t\t{migrate.RevisionTypeResolved, \"manually set\"},\n\t\t{migrate.RevisionTypeExecute | migrate.RevisionTypeResolved, \"applied + manually set\"},\n\t\t{migrate.RevisionTypeExecute | migrate.RevisionTypeBaseline, \"unknown (0011)\"},\n\t\t{1 << 3, \"unknown (1000)\"},\n\t} {\n\t\tac, err := tt.r.MarshalText()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, tt.ex, string(ac))\n\t}\n}\n\nfunc TestPlanner_WritePlan(t *testing.T) {\n\tp := t.TempDir()\n\td, err := migrate.NewLocalDir(p)\n\trequire.NoError(t, err)\n\tplan := &migrate.Plan{\n\t\tName: \"add_t1_and_t2\",\n\t\tChanges: []*migrate.Change{\n\t\t\t{Cmd: \"CREATE TABLE t1(c int)\", Reverse: \"DROP TABLE t1 IF EXISTS\"},\n\t\t\t{Cmd: \"CREATE TABLE t2(c int)\", Reverse: \"DROP TABLE t2\"},\n\t\t},\n\t}\n\n\t// DefaultFormatter\n\tpl := migrate.NewPlanner(nil, d, migrate.PlanWithChecksum(false))\n\trequire.NotNil(t, pl)\n\trequire.NoError(t, pl.WritePlan(plan))\n\tv := time.Now().UTC().Format(\"20060102150405\")\n\trequire.Equal(t, countFiles(t, d), 1)\n\trequireFileEqual(t, d, v+\"_add_t1_and_t2.sql\", \"CREATE TABLE t1(c int);\\nCREATE TABLE t2(c int);\\n\")\n\n\t// Custom formatter (creates \"up\" and \"down\" migration files).\n\tfmt, err := migrate.NewTemplateFormatter(\n\t\ttemplate.Must(template.New(\"\").Parse(\"{{ .Name }}.up.sql\")),\n\t\ttemplate.Must(template.New(\"\").Parse(\"{{ range .Changes }}{{ println .Cmd }}{{ end }}\")),\n\t\ttemplate.Must(template.New(\"\").Parse(\"{{ .Name }}.down.sql\")),\n\t\ttemplate.Must(template.New(\"\").Parse(\"{{ range .Changes }}{{ println .Reverse }}{{ end }}\")),\n\t)\n\trequire.NoError(t, err)\n\tpl = migrate.NewPlanner(nil, d, migrate.PlanFormat(fmt), migrate.PlanWithChecksum(false))\n\trequire.NotNil(t, pl)\n\trequire.NoError(t, pl.WritePlan(plan))\n\trequire.Equal(t, countFiles(t, d), 3)\n\trequireFileEqual(t, d, \"add_t1_and_t2.up.sql\", \"CREATE TABLE t1(c int)\\nCREATE TABLE t2(c int)\\n\")\n\trequireFileEqual(t, d, \"add_t1_and_t2.down.sql\", \"DROP TABLE t1 IF EXISTS\\nDROP TABLE t2\\n\")\n\n\t// With custom delimiter.\n\tplan.Delimiter = \"\\nGO\"\n\tpl = migrate.NewPlanner(nil, d, migrate.PlanWithChecksum(false))\n\trequire.NotNil(t, pl)\n\trequire.NoError(t, pl.WritePlan(plan))\n\tv = time.Now().UTC().Format(\"20060102150405\")\n\trequire.Equal(t, countFiles(t, d), 3)\n\trequireFileEqual(t, d, v+\"_add_t1_and_t2.sql\", \"-- atlas:delimiter \\\\nGO\\n\\nCREATE TABLE t1(c int)\\nGO\\nCREATE TABLE t2(c int)\\nGO\\n\")\n}\n\nfunc TestPlanner_WriteCheckpoint(t *testing.T) {\n\tp := t.TempDir()\n\td, err := migrate.NewLocalDir(p)\n\trequire.NoError(t, err)\n\tplan := &migrate.Plan{\n\t\tName: \"checkpoint\",\n\t\tChanges: []*migrate.Change{\n\t\t\t{Cmd: \"CREATE TABLE t1(c int)\", Reverse: \"DROP TABLE t1 IF EXISTS\"},\n\t\t\t{Cmd: \"CREATE TABLE t2(c int)\", Reverse: \"DROP TABLE t2\"},\n\t\t},\n\t}\n\n\t// DefaultFormatter\n\tpl := migrate.NewPlanner(nil, d)\n\trequire.NotNil(t, pl)\n\trequire.NoError(t, pl.WriteCheckpoint(plan, \"v1\"))\n\tfiles, err := d.Files()\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 1)\n\trequire.Equal(t, `-- atlas:checkpoint v1\n\nCREATE TABLE t1(c int);\nCREATE TABLE t2(c int);\n`, string(files[0].Bytes()))\n}\n\nfunc TestPlanner_Plan(t *testing.T) {\n\tvar (\n\t\tdrv = &mockDriver{}\n\t\tctx = context.Background()\n\t)\n\td, err := migrate.NewLocalDir(t.TempDir())\n\trequire.NoError(t, err)\n\n\t// nothing to do\n\tpl := migrate.NewPlanner(drv, d)\n\tplan, err := pl.Plan(ctx, \"empty\", migrate.Realm(nil))\n\trequire.ErrorIs(t, err, migrate.ErrNoPlan)\n\trequire.Nil(t, plan)\n\n\t// there are changes\n\tdrv.changes = []schema.Change{\n\t\t&schema.AddTable{T: schema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"c\", \"int\"))},\n\t\t&schema.AddTable{T: schema.NewTable(\"t2\").AddColumns(schema.NewIntColumn(\"c\", \"int\"))},\n\t}\n\tdrv.plan = &migrate.Plan{\n\t\tChanges: []*migrate.Change{\n\t\t\t{Cmd: \"CREATE TABLE t1(c int);\"},\n\t\t\t{Cmd: \"CREATE TABLE t2(c int);\"},\n\t\t},\n\t}\n\tplan, err = pl.Plan(ctx, \"\", migrate.Realm(nil))\n\trequire.NoError(t, err)\n\trequire.Equal(t, drv.plan, plan)\n}\n\nfunc TestPlanner_PlanSchema(t *testing.T) {\n\tvar (\n\t\tdrv = &mockDriver{}\n\t\tctx = context.Background()\n\t)\n\td, err := migrate.NewLocalDir(t.TempDir())\n\trequire.NoError(t, err)\n\n\t// Schema is missing in dev connection.\n\tpl := migrate.NewPlanner(drv, d)\n\tplan, err := pl.PlanSchema(ctx, \"empty\", migrate.Realm(nil))\n\trequire.EqualError(t, err, `not found`)\n\trequire.Nil(t, plan)\n\n\tdrv.realm = *schema.NewRealm(schema.New(\"test\"))\n\tpl = migrate.NewPlanner(drv, d)\n\tplan, err = pl.PlanSchema(ctx, \"empty\", migrate.Realm(schema.NewRealm()))\n\trequire.EqualError(t, err, `no schema was found in desired state`)\n\trequire.Nil(t, plan)\n\n\tdrv.realm = *schema.NewRealm(schema.New(\"test\"))\n\tpl = migrate.NewPlanner(drv, d)\n\tplan, err = pl.PlanSchema(ctx, \"empty\", migrate.Realm(schema.NewRealm(schema.New(\"test\"), schema.New(\"dev\"))))\n\trequire.EqualError(t, err, `2 schemas were found in desired state; expect 1`)\n\trequire.Nil(t, plan)\n\n\tdrv.realm = *schema.NewRealm(schema.New(\"test\"))\n\tpl = migrate.NewPlanner(drv, d)\n\tplan, err = pl.PlanSchema(ctx, \"multi\", migrate.Realm(schema.NewRealm(schema.New(\"test\"))))\n\trequire.ErrorIs(t, err, migrate.ErrNoPlan)\n\trequire.Nil(t, plan)\n}\n\nfunc TestPlanner_Checkpoint(t *testing.T) {\n\tvar (\n\t\tdrv = &mockDriver{}\n\t\tctx = context.Background()\n\t)\n\td, err := migrate.NewLocalDir(t.TempDir())\n\trequire.NoError(t, err)\n\n\t// Nothing to do.\n\tpl := migrate.NewPlanner(drv, d)\n\tplan, err := pl.Checkpoint(ctx, \"empty\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, &migrate.Plan{Name: \"empty\"}, plan)\n\n\t// There are changes.\n\tdrv.changes = []schema.Change{\n\t\t&schema.AddTable{T: schema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"c\", \"int\"))},\n\t\t&schema.AddTable{T: schema.NewTable(\"t2\").AddColumns(schema.NewIntColumn(\"c\", \"int\"))},\n\t}\n\tdrv.plan = &migrate.Plan{\n\t\tChanges: []*migrate.Change{\n\t\t\t{Cmd: \"CREATE TABLE t1(c int);\"},\n\t\t\t{Cmd: \"CREATE TABLE t2(c int);\"},\n\t\t},\n\t}\n\tplan, err = pl.Checkpoint(ctx, \"checkpoint\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, drv.plan, plan)\n}\n\nfunc TestPlanner_CheckpointSchema(t *testing.T) {\n\tvar (\n\t\tdrv = &mockDriver{}\n\t\tctx = context.Background()\n\t)\n\td, err := migrate.NewLocalDir(t.TempDir())\n\trequire.NoError(t, err)\n\n\t// Schema is missing in dev connection.\n\tpl := migrate.NewPlanner(drv, d)\n\tplan, err := pl.CheckpointSchema(ctx, \"empty\")\n\trequire.EqualError(t, err, `not found`)\n\trequire.Nil(t, plan)\n\n\tdrv.realm = *schema.NewRealm(schema.New(\"test\"))\n\tpl = migrate.NewPlanner(drv, d)\n\tplan, err = pl.CheckpointSchema(ctx, \"empty\")\n\trequire.Equal(t, &migrate.Plan{Name: \"empty\"}, plan)\n}\n\nfunc TestExecutor_ExecOrderLinear(t *testing.T) {\n\tvar (\n\t\tdrv = &mockDriver{}\n\t\tctx = context.Background()\n\t\trrw = &mockRevisionReadWriter{{Version: \"1\"}, {Version: \"2\"}, {Version: \"3\"}}\n\t\tdir = func(names ...string) migrate.Dir {\n\t\t\tm := &migrate.MemDir{}\n\t\t\tfor _, n := range names {\n\t\t\t\trequire.NoError(t, m.WriteFile(n, nil))\n\t\t\t}\n\t\t\th, err := m.Checksum()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, migrate.WriteSumFile(m, h))\n\t\t\treturn m\n\t\t}\n\t)\n\tt.Run(\"Linear\", func(t *testing.T) {\n\t\tex, err := migrate.NewExecutor(drv, dir(), rrw)\n\t\trequire.NoError(t, err)\n\t\tfiles, err := ex.Pending(ctx)\n\t\trequire.ErrorIs(t, err, migrate.ErrNoPendingFiles)\n\t\trequire.Empty(t, files)\n\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2.sql\", \"3.sql\"), rrw)\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.ErrorIs(t, err, migrate.ErrNoPendingFiles)\n\t\trequire.Empty(t, files)\n\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2.sql\", \"2.5.sql\", \"3.sql\"), rrw)\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.ErrorAs(t, err, new(*migrate.HistoryNonLinearError))\n\t\trequire.EqualError(t, err, \"migration file 2.5.sql was added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error\")\n\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2.sql\", \"2.5.sql\", \"2.6.sql\", \"3.sql\"), rrw)\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.ErrorAs(t, err, new(*migrate.HistoryNonLinearError))\n\t\trequire.EqualError(t, err, \"migration files 2.5.sql, 2.6.sql were added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error\")\n\n\t\t// The first file executed as checkpoint, therefore, 1.sql is not pending nor skipped.\n\t\trrw = &mockRevisionReadWriter{{Version: \"2\"}, {Version: \"3\"}}\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2_checkpoint.sql\", \"3.sql\"), rrw)\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.ErrorIs(t, err, migrate.ErrNoPendingFiles)\n\t\trequire.Empty(t, files)\n\n\t\t// The first file executed as checkpoint, therefore, 1.sql is not pending nor skipped.\n\t\trrw = &mockRevisionReadWriter{{Version: \"2\"}, {Version: \"3\"}}\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2_checkpoint.sql\", \"2.5.sql\", \"3.sql\"), rrw)\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.ErrorAs(t, err, new(*migrate.HistoryNonLinearError))\n\t\trequire.EqualError(t, err, \"migration file 2.5.sql was added out of order. See: https://atlasgo.io/versioned/apply#non-linear-error\")\n\t})\n\n\tt.Run(\"LinearSkipped\", func(t *testing.T) {\n\t\tex, err := migrate.NewExecutor(drv, dir(), rrw, migrate.WithExecOrder(migrate.ExecOrderLinearSkip))\n\t\trequire.NoError(t, err)\n\t\tfiles, err := ex.Pending(ctx)\n\t\trequire.ErrorIs(t, err, migrate.ErrNoPendingFiles)\n\t\trequire.Empty(t, files)\n\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2.sql\", \"3.sql\"), rrw, migrate.WithExecOrder(migrate.ExecOrderLinearSkip))\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.ErrorIs(t, err, migrate.ErrNoPendingFiles)\n\t\trequire.Empty(t, files)\n\n\t\t// File 2.5.sql is skipped.\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2.sql\", \"2.5.sql\", \"3.sql\"), rrw, migrate.WithExecOrder(migrate.ExecOrderLinearSkip))\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.ErrorIs(t, err, migrate.ErrNoPendingFiles)\n\t\trequire.Empty(t, files)\n\n\t\t// Files 2.5.sql and 2.6.sql are skipped.\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2.sql\", \"2.5.sql\", \"2.6.sql\", \"3.sql\"), rrw, migrate.WithExecOrder(migrate.ExecOrderLinearSkip))\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.ErrorIs(t, err, migrate.ErrNoPendingFiles)\n\t\trequire.Empty(t, files)\n\t})\n\n\tt.Run(\"NonLinear\", func(t *testing.T) {\n\t\tex, err := migrate.NewExecutor(drv, dir(), rrw, migrate.WithExecOrder(migrate.ExecOrderNonLinear))\n\t\trequire.NoError(t, err)\n\t\tfiles, err := ex.Pending(ctx)\n\t\trequire.ErrorIs(t, err, migrate.ErrNoPendingFiles)\n\t\trequire.Empty(t, files)\n\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2.sql\", \"3.sql\"), rrw, migrate.WithExecOrder(migrate.ExecOrderNonLinear))\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.ErrorIs(t, err, migrate.ErrNoPendingFiles)\n\t\trequire.Empty(t, files)\n\n\t\t// File 2.5.sql is pending.\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2.sql\", \"2.5.sql\", \"3.sql\"), rrw, migrate.WithExecOrder(migrate.ExecOrderNonLinear))\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 1)\n\t\trequire.Equal(t, \"2.5.sql\", files[0].Name())\n\n\t\t// Files 2.5.sql, 2.6.sql and 4.sql are pending.\n\t\tex, err = migrate.NewExecutor(drv, dir(\"1.sql\", \"2.sql\", \"2.5.sql\", \"2.6.sql\", \"3.sql\", \"4.sql\"), rrw, migrate.WithExecOrder(migrate.ExecOrderNonLinear))\n\t\trequire.NoError(t, err)\n\t\tfiles, err = ex.Pending(ctx)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, files, 3)\n\t\trequire.Equal(t, \"2.5.sql\", files[0].Name())\n\t\trequire.Equal(t, \"2.6.sql\", files[1].Name())\n\t\trequire.Equal(t, \"4.sql\", files[2].Name())\n\t})\n}\n\nfunc TestExecutor(t *testing.T) {\n\t// Passing nil raises error.\n\tex, err := migrate.NewExecutor(nil, nil, nil)\n\trequire.EqualError(t, err, \"sql/migrate: no driver given\")\n\trequire.Nil(t, ex)\n\n\tex, err = migrate.NewExecutor(&mockDriver{}, nil, nil)\n\trequire.EqualError(t, err, \"sql/migrate: no dir given\")\n\trequire.Nil(t, ex)\n\n\tdir, err := migrate.NewLocalDir(t.TempDir())\n\trequire.NoError(t, err)\n\tex, err = migrate.NewExecutor(&mockDriver{}, dir, nil)\n\trequire.EqualError(t, err, \"sql/migrate: no revision storage given\")\n\trequire.Nil(t, ex)\n\n\t// Does not operate on invalid migration dir.\n\tdir, err = migrate.NewLocalDir(t.TempDir())\n\trequire.NoError(t, err)\n\trequire.NoError(t, dir.WriteFile(\"atlas.sum\", hash))\n\tex, err = migrate.NewExecutor(&mockDriver{}, dir, &mockRevisionReadWriter{}, migrate.WithOperatorVersion(\"op\"))\n\trequire.NoError(t, err)\n\trequire.NotNil(t, ex)\n\trequire.ErrorIs(t, ex.ExecuteN(context.Background(), 0), migrate.ErrChecksumMismatch)\n\trequire.EqualError(t, ex.ExecuteTo(context.Background(), \"1\"), `sql/migrate: migration with version \"1\" not found`)\n\n\t// Prerequisites.\n\tvar (\n\t\tdrv  = &mockDriver{}\n\t\trrw  = &mockRevisionReadWriter{}\n\t\tlog  = &mockLogger{}\n\t\trev1 = &migrate.Revision{\n\t\t\tVersion:         \"1.a\",\n\t\t\tDescription:     \"sub.up\",\n\t\t\tType:            migrate.RevisionTypeExecute,\n\t\t\tApplied:         2,\n\t\t\tTotal:           2,\n\t\t\tHash:            \"nXyZR020M/mH7LxkoTkJr7BcQkipVg90imQ9I4595dw=\",\n\t\t\tOperatorVersion: \"op\",\n\t\t}\n\t\trev2 = &migrate.Revision{\n\t\t\tVersion:         \"2.10.x-20\",\n\t\t\tDescription:     \"description\",\n\t\t\tType:            migrate.RevisionTypeExecute,\n\t\t\tApplied:         1,\n\t\t\tTotal:           1,\n\t\t\tHash:            \"wQB3Vh3PHVXQg9OD3Gn7TBxbZN3r1Qb7TtAE1g3q9mQ=\",\n\t\t\tOperatorVersion: \"op\",\n\t\t}\n\t)\n\tdir, err = migrate.NewLocalDir(filepath.Join(\"testdata\", \"migrate\", \"sub\"))\n\trequire.NoError(t, err)\n\tex, err = migrate.NewExecutor(drv, dir, rrw, migrate.WithLogger(log), migrate.WithOperatorVersion(\"op\"))\n\trequire.NoError(t, err)\n\n\t// Applies two of them.\n\trequire.NoError(t, ex.ExecuteN(context.Background(), 2))\n\trequire.Equal(t, drv.executed, []string{\n\t\t\"CREATE TABLE t_sub(c int);\", \"ALTER TABLE t_sub ADD c1 int;\", \"ALTER TABLE t_sub ADD c2 int;\",\n\t})\n\trequireEqualRevisions(t, []*migrate.Revision{rev1, rev2}, *rrw)\n\trequire.Len(t, *log, 7)\n\trequire.IsType(t, migrate.LogExecution{}, (*log)[0])\n\trequire.Equal(t, \"2.10.x-20\", (*log)[0].(migrate.LogExecution).To)\n\trequire.Len(t, (*log)[0].(migrate.LogExecution).Files, 2)\n\trequire.Equal(t, \"1.a_sub.up.sql\", (*log)[0].(migrate.LogExecution).Files[0].Name())\n\trequire.Equal(t, \"2.10.x-20_description.sql\", (*log)[0].(migrate.LogExecution).Files[1].Name())\n\trequire.IsType(t, migrate.LogFile{}, (*log)[1])\n\trequire.Equal(t, migrate.LogStmt{\n\t\tSQL:  \"CREATE TABLE t_sub(c int);\",\n\t\tStmt: &migrate.Stmt{Pos: 24, Text: \"CREATE TABLE t_sub(c int);\", Comments: []string{\"-- create table \\\"t_sub\\\"\\n\"}},\n\t}, (*log)[2])\n\trequire.Equal(t, migrate.LogStmt{\n\t\tSQL:  \"ALTER TABLE t_sub ADD c1 int;\",\n\t\tStmt: &migrate.Stmt{Pos: 68, Text: \"ALTER TABLE t_sub ADD c1 int;\", Comments: []string{\"-- add c1 column\\n\"}},\n\t}, (*log)[3])\n\trequire.IsType(t, migrate.LogFile{}, (*log)[4])\n\trequire.Equal(t, migrate.LogStmt{\n\t\tSQL:  \"ALTER TABLE t_sub ADD c2 int;\",\n\t\tStmt: &migrate.Stmt{Pos: 17, Text: \"ALTER TABLE t_sub ADD c2 int;\", Comments: []string{\"-- add c2 column\\n\"}},\n\t}, (*log)[5])\n\trequire.Equal(t, migrate.LogDone{}, (*log)[6])\n\n\t// Partly is pending.\n\tp, err := ex.Pending(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, p, 1)\n\trequire.Equal(t, \"3_partly.sql\", p[0].Name())\n\n\t// Apply one by one.\n\t*rrw = mockRevisionReadWriter{}\n\t*drv = mockDriver{}\n\n\trequire.NoError(t, ex.ExecuteN(context.Background(), 1))\n\trequire.Equal(t, []string{\"CREATE TABLE t_sub(c int);\", \"ALTER TABLE t_sub ADD c1 int;\"}, drv.executed)\n\trequireEqualRevisions(t, []*migrate.Revision{rev1}, *rrw)\n\n\trequire.NoError(t, ex.ExecuteN(context.Background(), 1))\n\trequire.Equal(t, []string{\n\t\t\"CREATE TABLE t_sub(c int);\", \"ALTER TABLE t_sub ADD c1 int;\", \"ALTER TABLE t_sub ADD c2 int;\",\n\t}, drv.executed)\n\trequireEqualRevisions(t, []*migrate.Revision{rev1, rev2}, *rrw)\n\n\t// Partly is pending.\n\tp, err = ex.Pending(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, p, 1)\n\trequire.Equal(t, \"3_partly.sql\", p[0].Name())\n\n\t// Suppose first revision is already executed, only execute second migration file.\n\t*rrw = []*migrate.Revision{rev1}\n\t*drv = mockDriver{}\n\n\trequire.NoError(t, ex.ExecuteN(context.Background(), 1))\n\trequire.Equal(t, []string{\"ALTER TABLE t_sub ADD c2 int;\"}, drv.executed)\n\trequireEqualRevisions(t, []*migrate.Revision{rev1, rev2}, *rrw)\n\n\t// Partly is pending.\n\tp, err = ex.Pending(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, p, 1)\n\trequire.Equal(t, \"3_partly.sql\", p[0].Name())\n\n\t// Failing, counter will be correct.\n\t*rrw = []*migrate.Revision{rev1, rev2}\n\t*drv = mockDriver{}\n\tdrv.failOn(2, errors.New(\"this is an error\"))\n\trequire.ErrorContains(t, ex.ExecuteN(context.Background(), 1), \"this is an error\")\n\trevs, err := rrw.ReadRevisions(context.Background())\n\trequire.NoError(t, err)\n\trequireEqualRevision(t, &migrate.Revision{\n\t\tVersion:         \"3\",\n\t\tDescription:     \"partly\",\n\t\tType:            migrate.RevisionTypeExecute,\n\t\tApplied:         1,\n\t\tTotal:           2,\n\t\tError:           \"this is an error\",\n\t\tErrorStmt:       \"ALTER TABLE t_sub ADD c4 int;\",\n\t\tOperatorVersion: \"op\",\n\t}, revs[len(revs)-1])\n\n\terr = ex.ExecuteTo(context.Background(), \"3.sql\")\n\trequire.EqualError(t, err, `sql/migrate: migration with version \"3.sql\" not found. Did you mean \"3\"?`)\n\terr = ex.ExecuteTo(context.Background(), \"7\")\n\trequire.EqualError(t, err, `sql/migrate: migration with version \"7\" not found`)\n\n\t// Will fail if applied contents hash has changed (like when editing a partially applied file to fix an error).\n\th := revs[len(revs)-1].PartialHashes[0]\n\trevs[len(revs)-1].PartialHashes[0] += h\n\trequire.ErrorAs(t, ex.ExecuteN(context.Background(), 1), &migrate.HistoryChangedError{})\n\n\t// Re-attempting to migrate will pick up where the execution was left off.\n\trevs[len(revs)-1].PartialHashes[0] = h\n\t*drv = mockDriver{}\n\trequire.NoError(t, ex.ExecuteN(context.Background(), 1))\n\trequire.Equal(t, []string{\"ALTER TABLE t_sub ADD c4 int;\"}, drv.executed)\n\trequire.Nil(t, revs[len(revs)-1].PartialHashes) // cleared our on successful apply\n\n\t// Everything is applied.\n\trequire.ErrorIs(t, ex.ExecuteN(context.Background(), 0), migrate.ErrNoPendingFiles)\n\n\t// Test ExecuteTo.\n\t*rrw = []*migrate.Revision{}\n\t*drv = mockDriver{}\n\trequire.EqualError(t, ex.ExecuteTo(context.Background(), \"\"), \"sql/migrate: migration with version \\\"\\\" not found\")\n\trequire.NoError(t, ex.ExecuteTo(context.Background(), \"2.10.x-20\"))\n\trequireEqualRevisions(t, []*migrate.Revision{rev1, rev2}, *rrw)\n\n\t// Failed storing initial revision state in the database.\n\tlog = &mockLogger{}\n\t*rrw = []*migrate.Revision{}\n\tex, err = migrate.NewExecutor(\n\t\t&mockDriver{}, dir,\n\t\t&mockWriteRevisionError{\n\t\t\tmockRevisionReadWriter: *rrw,\n\t\t\terrinit:                errors.New(\"init error\"),\n\t\t},\n\t\tmigrate.WithLogger(log),\n\t)\n\trequire.NoError(t, err)\n\terr = ex.ExecuteTo(context.Background(), \"2.10.x-20\")\n\trequire.EqualError(t, err, `sql/migrate: write revision: init error`)\n\trequire.Len(t, *log, 2, \"fail on init\")\n\trequire.IsType(t, migrate.LogExecution{}, (*log)[0])\n\trequire.IsType(t, migrate.LogError{}, (*log)[1])\n\te1 := (*log)[1].(migrate.LogError)\n\trequire.EqualError(t, e1.Error, `sql/migrate: write revision: init error`)\n\n\t// Failed storing applied revision state in the database.\n\tlog = &mockLogger{}\n\t*rrw = []*migrate.Revision{}\n\tex, err = migrate.NewExecutor(\n\t\t&mockDriver{}, dir,\n\t\t&mockWriteRevisionError{\n\t\t\tmockRevisionReadWriter: *rrw,\n\t\t\terrdone:                errors.New(\"done error\"),\n\t\t},\n\t\tmigrate.WithLogger(log),\n\t)\n\trequire.NoError(t, err)\n\terr = ex.ExecuteTo(context.Background(), \"2.10.x-20\")\n\trequire.EqualError(t, err, `sql/migrate: write revision: done error`)\n\t// Logs are: Intro/Execution, File, 2 Stmts (1.a_sub.up.sql),\n\t// and Error when writing the revision of the first file.\n\trequire.Len(t, *log, 5, \"expect 5 logs to be fired\")\n\trequire.IsType(t, migrate.LogExecution{}, (*log)[0])\n\trequire.IsType(t, migrate.LogFile{}, (*log)[1])\n\trequire.IsType(t, migrate.LogStmt{}, (*log)[2])\n\trequire.IsType(t, migrate.LogStmt{}, (*log)[3])\n\te1 = (*log)[4].(migrate.LogError)\n\trequire.EqualError(t, e1.Error, `sql/migrate: write revision: done error`)\n\trequire.EqualError(t, errors.Unwrap(e1.Error), `done error`)\n\n\t// Successful retry should reset the error.\n\tmem := &migrate.MemDir{}\n\trequire.NoError(t, mem.WriteFile(\"1.sql\", []byte(\"CREATE TABLE t(c int);\")))\n\tsum, err := mem.Checksum()\n\trequire.NoError(t, err)\n\trequire.NoError(t, migrate.WriteSumFile(mem, sum))\n\t*rrw = []*migrate.Revision{{Version: \"1\", Error: \"error\", ErrorStmt: \";CREATE TABLE t(c int);\", Applied: 0, Total: 1}}\n\tex, err = migrate.NewExecutor(&mockDriver{}, mem, rrw, migrate.WithLogger(log))\n\trequire.NoError(t, err)\n\terr = ex.ExecuteTo(context.Background(), \"1\")\n\trequire.NoError(t, err)\n\trequire.Empty(t, (*rrw)[0].Error)\n\trequire.Empty(t, (*rrw)[0].ErrorStmt)\n}\n\nfunc TestExecutor_Baseline(t *testing.T) {\n\tvar (\n\t\trrw mockRevisionReadWriter\n\t\tdrv = &mockDriver{dirty: true}\n\t\tlog = &mockLogger{}\n\t)\n\tdir, err := migrate.NewLocalDir(filepath.Join(\"testdata/migrate\", \"sub\"))\n\trequire.NoError(t, err)\n\tex, err := migrate.NewExecutor(drv, dir, &rrw, migrate.WithLogger(log))\n\trequire.NoError(t, err)\n\n\t// Require baseline-version or explicit flag to work on a dirty workspace.\n\tfiles, err := ex.Pending(context.Background())\n\trequire.EqualError(t, err, \"sql/migrate: connected database is not clean: found table. baseline version or allow-dirty is required\")\n\trequire.Nil(t, files)\n\n\trrw = mockRevisionReadWriter{}\n\tex, err = migrate.NewExecutor(drv, dir, &rrw, migrate.WithLogger(log), migrate.WithAllowDirty(true))\n\trequire.NoError(t, err)\n\tfiles, err = ex.Pending(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 3)\n\n\trrw = mockRevisionReadWriter{}\n\tex, err = migrate.NewExecutor(drv, dir, &rrw, migrate.WithLogger(log), migrate.WithBaselineVersion(\"2.10.x-20\"))\n\trequire.NoError(t, err)\n\tfiles, err = ex.Pending(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, files, 1)\n\trequire.Len(t, rrw, 1)\n\trequire.Equal(t, \"2.10.x-20\", rrw[0].Version)\n\trequire.Equal(t, \"description\", rrw[0].Description)\n\trequire.Equal(t, migrate.RevisionTypeBaseline, rrw[0].Type)\n\n\trrw = mockRevisionReadWriter{}\n\tex, err = migrate.NewExecutor(drv, dir, &rrw, migrate.WithLogger(log), migrate.WithBaselineVersion(\"3\"))\n\trequire.NoError(t, err)\n\tfiles, err = ex.Pending(context.Background())\n\trequire.ErrorIs(t, err, migrate.ErrNoPendingFiles)\n\trequire.Len(t, rrw, 1)\n\trequire.Equal(t, \"3\", rrw[0].Version)\n\trequire.Equal(t, \"partly\", rrw[0].Description)\n\trequire.Equal(t, migrate.RevisionTypeBaseline, rrw[0].Type)\n}\n\ntype (\n\tmockDriver struct {\n\t\tmigrate.Driver\n\t\tplan        *migrate.Plan\n\t\tchanges     []schema.Change\n\t\tapplied     []schema.Change\n\t\trealm       schema.Realm\n\t\texecuted    []string\n\t\tfailCounter int\n\t\tfailWith    error\n\t\tdirty       bool\n\t}\n)\n\n// the nth call to ExecContext will fail with the given error.\nfunc (m *mockDriver) failOn(n int, err error) {\n\tm.failCounter = n\n\tm.failWith = err\n}\n\nfunc (m *mockDriver) ExecContext(_ context.Context, query string, _ ...any) (sql.Result, error) {\n\tif m.failCounter > 0 {\n\t\tm.failCounter--\n\t\tif m.failCounter == 0 {\n\t\t\treturn nil, m.failWith\n\t\t}\n\t}\n\tm.executed = append(m.executed, query)\n\treturn nil, nil\n}\n\nfunc (m *mockDriver) InspectSchema(context.Context, string, *schema.InspectOptions) (*schema.Schema, error) {\n\tif len(m.realm.Schemas) == 0 {\n\t\treturn nil, schema.NotExistError{Err: errors.New(\"not found\")}\n\t}\n\treturn m.realm.Schemas[0], nil\n}\n\nfunc (m *mockDriver) InspectRealm(context.Context, *schema.InspectRealmOption) (*schema.Realm, error) {\n\treturn &m.realm, nil\n}\n\nfunc (m *mockDriver) SchemaDiff(_, _ *schema.Schema, _ ...schema.DiffOption) ([]schema.Change, error) {\n\treturn m.changes, nil\n}\n\nfunc (m *mockDriver) RealmDiff(_, _ *schema.Realm, _ ...schema.DiffOption) ([]schema.Change, error) {\n\treturn m.changes, nil\n}\n\nfunc (m *mockDriver) PlanChanges(context.Context, string, []schema.Change, ...migrate.PlanOption) (*migrate.Plan, error) {\n\treturn m.plan, nil\n}\n\nfunc (m *mockDriver) ApplyChanges(_ context.Context, changes []schema.Change, _ ...migrate.PlanOption) error {\n\tm.applied = changes\n\treturn nil\n}\n\nfunc (m *mockDriver) Snapshot(context.Context) (migrate.RestoreFunc, error) {\n\tif m.dirty {\n\t\treturn nil, &migrate.NotCleanError{}\n\t}\n\trealm := m.realm\n\treturn func(context.Context) error {\n\t\tm.realm = realm\n\t\treturn nil\n\t}, nil\n}\n\nfunc (m *mockDriver) CheckClean(context.Context, *migrate.TableIdent) error {\n\tif m.dirty {\n\t\treturn &migrate.NotCleanError{Reason: \"found table\"}\n\t}\n\treturn nil\n}\n\ntype mockRevisionReadWriter []*migrate.Revision\n\nfunc (*mockRevisionReadWriter) Ident() *migrate.TableIdent {\n\treturn nil\n}\n\nfunc (*mockRevisionReadWriter) Exists(_ context.Context) (bool, error) {\n\treturn true, nil\n}\n\nfunc (*mockRevisionReadWriter) Init(_ context.Context) error {\n\treturn nil\n}\n\nfunc (rrw *mockRevisionReadWriter) WriteRevision(_ context.Context, r *migrate.Revision) error {\n\tfor i, rev := range *rrw {\n\t\tif rev.Version == r.Version {\n\t\t\t(*rrw)[i] = r\n\t\t\treturn nil\n\t\t}\n\t}\n\t*rrw = append(*rrw, r)\n\treturn nil\n}\n\nfunc (rrw *mockRevisionReadWriter) ReadRevision(_ context.Context, v string) (*migrate.Revision, error) {\n\tfor _, r := range *rrw {\n\t\tif r.Version == v {\n\t\t\treturn r, nil\n\t\t}\n\t}\n\treturn nil, migrate.ErrRevisionNotExist\n}\n\nfunc (rrw *mockRevisionReadWriter) DeleteRevision(_ context.Context, v string) error {\n\ti := -1\n\tfor j, r := range *rrw {\n\t\tif r.Version == v {\n\t\t\ti = j\n\t\t\tbreak\n\t\t}\n\t}\n\tif i == -1 {\n\t\treturn nil\n\t}\n\tcopy((*rrw)[i:], (*rrw)[i+1:])\n\t*rrw = (*rrw)[:len(*rrw)-1]\n\treturn nil\n}\n\nfunc (rrw *mockRevisionReadWriter) ReadRevisions(context.Context) ([]*migrate.Revision, error) {\n\treturn *rrw, nil\n}\n\nfunc (rrw *mockRevisionReadWriter) clean() {\n\t*rrw = []*migrate.Revision{}\n}\n\ntype mockWriteRevisionError struct {\n\tmockRevisionReadWriter\n\terrinit, errdone error // error on init and done\n}\n\nfunc (m *mockWriteRevisionError) WriteRevision(ctx context.Context, r *migrate.Revision) error {\n\tswitch {\n\tcase r.Applied == 0 && m.errinit != nil:\n\t\treturn m.errinit\n\tcase r.Applied == r.Total && m.errdone != nil:\n\t\treturn m.errdone\n\tdefault:\n\t\treturn m.mockRevisionReadWriter.WriteRevision(ctx, r)\n\t}\n}\n\ntype mockLogger []migrate.LogEntry\n\nfunc (m *mockLogger) Log(e migrate.LogEntry) { *m = append(*m, e) }\n\nfunc requireEqualRevisions(t *testing.T, expected, actual []*migrate.Revision) {\n\trequire.Equal(t, len(expected), len(actual))\n\tfor i := range expected {\n\t\trequireEqualRevision(t, expected[i], actual[i])\n\t}\n}\n\nfunc requireEqualRevision(t *testing.T, expected, actual *migrate.Revision) {\n\trequire.Equal(t, expected.Version, actual.Version)\n\trequire.Equal(t, expected.Description, actual.Description)\n\trequire.Equal(t, expected.Type, actual.Type)\n\trequire.Equal(t, expected.Applied, actual.Applied)\n\trequire.Equal(t, expected.Total, actual.Total)\n\trequire.Equal(t, expected.Error, actual.Error)\n\tif expected.Hash != \"\" {\n\t\trequire.Equal(t, expected.Hash, actual.Hash)\n\t}\n\trequire.Equal(t, expected.OperatorVersion, actual.OperatorVersion)\n}\n\nfunc countFiles(t *testing.T, d migrate.Dir) int {\n\tfiles, err := fs.ReadDir(d, \"\")\n\trequire.NoError(t, err)\n\treturn len(files)\n}\n\nfunc requireFileEqual(t *testing.T, d migrate.Dir, name, contents string) {\n\tc, err := fs.ReadFile(d, name)\n\trequire.NoError(t, err)\n\trequire.Equal(t, contents, string(c))\n}\n"
  },
  {
    "path": "sql/migrate/testdata/golang-migrate/1_base.up.sql",
    "content": "CREATE TABLE t(c int);"
  },
  {
    "path": "sql/migrate/testdata/lex/1.sql",
    "content": "CREATE TABLE t1(id int);\n\n\nCREATE TABLE t2(id int);\n\nCREATE TABLE t3(id int);\n\nCREATE TABLE t4(\n    id int,\n    name varchar(255)\n);\n\nCREATE TABLE t4(\n    id int,\n    `name` varchar(255) DEFAULT ';'\n) ENGINE=InnoDB;\n\nCREATE TABLE t5(\n    id int\n    /* comment */\n    -- comment\n) ENGINE=InnoDB;"
  },
  {
    "path": "sql/migrate/testdata/lex/1.sql.golden",
    "content": "CREATE TABLE t1(id int);\n-- end --\nCREATE TABLE t2(id int);\n-- end --\nCREATE TABLE t3(id int);\n-- end --\nCREATE TABLE t4(\n    id int,\n    name varchar(255)\n);\n-- end --\nCREATE TABLE t4(\n    id int,\n    `name` varchar(255) DEFAULT ';'\n) ENGINE=InnoDB;\n-- end --\nCREATE TABLE t5(\n    id int\n    /* comment */\n    -- comment\n) ENGINE=InnoDB;"
  },
  {
    "path": "sql/migrate/testdata/lex/10_delimiter_comment.sql",
    "content": "-- atlas:delimiter -- end\n\nCREATE PROCEDURE dorepeat(p1 INT)\nBEGIN\n    SET @x = 0;\n    REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;\nEND;\n-- end\nCALL dorepeat(1000);\n"
  },
  {
    "path": "sql/migrate/testdata/lex/10_delimiter_comment.sql.golden",
    "content": "CREATE PROCEDURE dorepeat(p1 INT)\nBEGIN\n    SET @x = 0;\n    REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;\nEND;\n-- end --\nCALL dorepeat(1000);"
  },
  {
    "path": "sql/migrate/testdata/lex/11_delimiter_mysql_command.sql",
    "content": "-- An example for supporting MySQL client delimiters.\n\nDELIMITER $$\n\nCREATE OR REPLACE FUNCTION gen_uuid() RETURNS VARCHAR(22)\nBEGIN\n    RETURN concat(\n        date_format(NOW(6), '%Y%m%d%i%s%f'),\n        ROUND(1 + RAND() * (100 - 2))\n    );\nEND;$$\n\nDELIMITER ;\n\nCALL gen_uuid();\n"
  },
  {
    "path": "sql/migrate/testdata/lex/11_delimiter_mysql_command.sql.golden",
    "content": "CREATE OR REPLACE FUNCTION gen_uuid() RETURNS VARCHAR(22)\nBEGIN\n    RETURN concat(\n        date_format(NOW(6), '%Y%m%d%i%s%f'),\n        ROUND(1 + RAND() * (100 - 2))\n    );\nEND;\n-- end --\nCALL gen_uuid();"
  },
  {
    "path": "sql/migrate/testdata/lex/12_delimiter_mysql_command.sql",
    "content": "delimiter //\ncreate table t2 (a int) //\n\ndelimiter ;\ndelimiter //\n\ncreate table t3 (a int) //\ndelimiter ;\n\nshow tables;\ndrop table t2, t3;\n"
  },
  {
    "path": "sql/migrate/testdata/lex/12_delimiter_mysql_command.sql.golden",
    "content": "create table t2 (a int)\n-- end --\ncreate table t3 (a int)\n-- end --\nshow tables;\n-- end --\ndrop table t2, t3;"
  },
  {
    "path": "sql/migrate/testdata/lex/13_delimiter_mysql_command.sql",
    "content": "# Test delimiter :\nselect \"Test delimiter :\" as \" \";\ndelimiter :\nselect * from t1:\n/* Delimiter commands can have comments */\ndelimiter ;\nselect 'End test :';\n\n/* Test delimiter :; */\nselect \"Test delimiter :;\" as \" \";\ndelimiter :;\nselect * from t1 :;\ndelimiter ;\nselect 'End test :;';\n\n-- Test delimiter //\nselect \"Test delimiter //\" as \" \";\ndelimiter //\nselect * from t1//\ndelimiter ;\nselect 'End test //';\n\n# Test delimiter 'MySQL'\nselect \"Test delimiter MySQL\" as \" \";\ndelimiter 'MySQL'\nselect * from t1MySQL\ndelimiter ;\nselect 'End test MySQL';\n\n# Test delimiter 'delimiter'\nselect \"Test delimiter delimiter\" as \" \";\ndelimiter delimiter\nselect * from t1delimiter\ndelimiter ;\nselect 'End test delimiter';\n\n# Test delimiter @@\nselect \"Test delimiter @@\" as \" \";\ndelimiter @@\nselect * from t1 @@\nselect * from t2@@\nalter table t add column c@@\ndelimiter ;\nselect 'End test @@';\n\n# Test delimiter \\n\\n\nselect \"Test delimiter \\n\\n\" as \" \";\ndelimiter \\n\\n\nselect * from t1\n\nselect * from t2\n\ndelimiter ;\nselect 'End test \\\\n\\\\n';"
  },
  {
    "path": "sql/migrate/testdata/lex/13_delimiter_mysql_command.sql.golden",
    "content": "select \"Test delimiter :\" as \" \";\n-- end --\nselect * from t1\n-- end --\nselect 'End test :';\n-- end --\nselect \"Test delimiter :;\" as \" \";\n-- end --\nselect * from t1\n-- end --\nselect 'End test :;';\n-- end --\nselect \"Test delimiter //\" as \" \";\n-- end --\nselect * from t1\n-- end --\nselect 'End test //';\n-- end --\nselect \"Test delimiter MySQL\" as \" \";\n-- end --\nselect * from t1\n-- end --\nselect 'End test MySQL';\n-- end --\nselect \"Test delimiter delimiter\" as \" \";\n-- end --\nselect * from t1\n-- end --\nselect 'End test delimiter';\n-- end --\nselect \"Test delimiter @@\" as \" \";\n-- end --\nselect * from t1\n-- end --\nselect * from t2\n-- end --\nalter table t add column c\n-- end --\nselect 'End test @@';\n-- end --\nselect \"Test delimiter \\n\\n\" as \" \";\n-- end --\nselect * from t1\n-- end --\nselect * from t2\n-- end --\nselect 'End test \\\\n\\\\n';"
  },
  {
    "path": "sql/migrate/testdata/lex/14_delimiter_mysql_command.sql",
    "content": "DELIMITER //\nCREATE PROCEDURE dorepeat(p1 INT)\n    BEGIN\n    SET @x = 0;\n    REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;\nEND\n//\nDELIMITER ;\nCALL dorepeat(100)"
  },
  {
    "path": "sql/migrate/testdata/lex/14_delimiter_mysql_command.sql.golden",
    "content": "CREATE PROCEDURE dorepeat(p1 INT)\n    BEGIN\n    SET @x = 0;\n    REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;\nEND\n-- end --\nCALL dorepeat(100)"
  },
  {
    "path": "sql/migrate/testdata/lex/15_dollar_quote.sql",
    "content": "create function tcl_date_week(int4,int4,int4) returns text as $$\n    return [clock format [clock scan \"$2/$3/$1\"] -format \"%U\"]\n$$ language pltcl immutable;\ncreate function tclsnitch() returns event_trigger language pltcl as $$\n  elog NOTICE \"tclsnitch: $TG_event $TG_tag\"\n$$;\n\ncreate function foobar() returns int language sql as $$select 1;$$;\n\ncreate function tcl_composite_arg_ref2(T_comp1) returns text as '\n    return $1(ref2)\n' language pltcl;\n\ncreate function tcl_error_handling_test(text) returns text\nlanguage pltcl\nas $function$\n    if {[catch $1 err]} {\n        if {[lindex $::errorCode 0] != \"POSTGRES\"} {\n            return $err\n        }\n        array set myArray $::errorCode\n        unset myArray(POSTGRES)\n        unset -nocomplain myArray(funcname)\n        unset -nocomplain myArray(filename)\n        unset -nocomplain myArray(lineno)\n\n# A comment.\nset vals []\n    foreach {key} [lsort [array names myArray]] {\nset value [string map {\"\\n\" \"\\n\\t\"} $myArray($key)]\n            lappend vals \"$key: $value\"\n        }\n        return [join $vals \"\\n\"]\n    } else {\n        return \"no error\"\n    }\n$function$;\n\ncreate function tcl_spi_exec(\n    prepare boolean,\n    action text\n)\n    returns void language pltcl AS $function$\nset query \"select * from (values (1,'foo'),(2,'bar'),(3,'baz')) v(col1,col2)\"\n    if {$1 == \"t\"} {\nset prep [spi_prepare $query {}]\n    spi_execp -array A $prep {\n        elog NOTICE \"col1 $A(col1), col2 $A(col2)\"\n\n        switch $A(col1) {\n            2 {\n                elog NOTICE \"action: $2\"\n                switch $2 {\n                    break {\n                        break\n                    }\n                    continue {\n                        continue\n                    }\n                    return {\n                        return\n                    }\n                    error {\n                        error \"error message\"\n                    }\n                }\n                error \"should not get here\"\n            }\n        }\n    }\n} else {\n    spi_exec -array A $query {\n        elog NOTICE \"col1 $A(col1), col2 $A(col2)\"\n\n        switch $A(col1) {\n            2 {\n                elog NOTICE \"action: $2\"\n                switch $2 {\n                    break {\n                        break\n                    }\n                    continue {\n                        continue\n                    }\n                    return {\n                        return\n                    }\n                    error {\n                        error \"error message\"\n                    }\n                }\n                error \"should not get here\"\n            }\n        }\n    }\n}\nelog NOTICE \"end of function\"\n$function$;\n\nDO $$ BEGIN\nCREATE TYPE some-type AS ENUM ('some-val-1', 'some-val-2');\nEXCEPTION\n    WHEN duplicate_object THEN null;\nEND; $$;\n\nDO $$DECLARE r record;\nBEGIN\n    FOR r IN SELECT table_schema, table_name FROM information_schema.tables\n             WHERE table_type = 'VIEW' AND table_schema = 'public'\n    LOOP\n        EXECUTE 'GRANT ALL ON ' || quote_ident(r.table_schema) || '.' || quote_ident(r.table_name) || ' TO webuser';\n    END LOOP;\nEND$$;\n\n# Shorter examples.\nSELECT * FROM table WHERE name = $$John Doe$$;\nSELECT * FROM table WHERE name = $a1$John Doe$a1$;\nUPDATE table SET description = $$Lorem ipsum dolor sit amet$$ WHERE id = 123;\nINSERT INTO table (name, description) VALUES ($$Jane Smith$$, $$This is Jane's description$$);\nCREATE INDEX index ON table (c);\nCREATE TRIGGER trigger BEFORE INSERT ON table FOR EACH ROW EXECUTE FUNCTION function(params);\nSELECT COUNT(*) FROM table WHERE description ILIKE $$%foo%$$;\nCREATE FUNCTION my_function() RETURNS void AS $$\nBEGIN\n   -- function body here\nEND;\n$$ LANGUAGE plpgsql;\n\nCREATE OR REPLACE FUNCTION f1(target regclass)\n  RETURNS VOID AS $BEGIN$\nDECLARE\ntable_name TEXT := quote_ident(target :: text);\nBEGIN\nEXECUTE 'alter table ' || table_name || ' add column id serial';\nEND;\n$BEGIN$\nLANGUAGE plpgsql;"
  },
  {
    "path": "sql/migrate/testdata/lex/15_dollar_quote.sql.golden",
    "content": "create function tcl_date_week(int4,int4,int4) returns text as $$\n    return [clock format [clock scan \"$2/$3/$1\"] -format \"%U\"]\n$$ language pltcl immutable;\n-- end --\ncreate function tclsnitch() returns event_trigger language pltcl as $$\n  elog NOTICE \"tclsnitch: $TG_event $TG_tag\"\n$$;\n-- end --\ncreate function foobar() returns int language sql as $$select 1;$$;\n-- end --\ncreate function tcl_composite_arg_ref2(T_comp1) returns text as '\n    return $1(ref2)\n' language pltcl;\n-- end --\ncreate function tcl_error_handling_test(text) returns text\nlanguage pltcl\nas $function$\n    if {[catch $1 err]} {\n        if {[lindex $::errorCode 0] != \"POSTGRES\"} {\n            return $err\n        }\n        array set myArray $::errorCode\n        unset myArray(POSTGRES)\n        unset -nocomplain myArray(funcname)\n        unset -nocomplain myArray(filename)\n        unset -nocomplain myArray(lineno)\n\n# A comment.\nset vals []\n    foreach {key} [lsort [array names myArray]] {\nset value [string map {\"\\n\" \"\\n\\t\"} $myArray($key)]\n            lappend vals \"$key: $value\"\n        }\n        return [join $vals \"\\n\"]\n    } else {\n        return \"no error\"\n    }\n$function$;\n-- end --\ncreate function tcl_spi_exec(\n    prepare boolean,\n    action text\n)\n    returns void language pltcl AS $function$\nset query \"select * from (values (1,'foo'),(2,'bar'),(3,'baz')) v(col1,col2)\"\n    if {$1 == \"t\"} {\nset prep [spi_prepare $query {}]\n    spi_execp -array A $prep {\n        elog NOTICE \"col1 $A(col1), col2 $A(col2)\"\n\n        switch $A(col1) {\n            2 {\n                elog NOTICE \"action: $2\"\n                switch $2 {\n                    break {\n                        break\n                    }\n                    continue {\n                        continue\n                    }\n                    return {\n                        return\n                    }\n                    error {\n                        error \"error message\"\n                    }\n                }\n                error \"should not get here\"\n            }\n        }\n    }\n} else {\n    spi_exec -array A $query {\n        elog NOTICE \"col1 $A(col1), col2 $A(col2)\"\n\n        switch $A(col1) {\n            2 {\n                elog NOTICE \"action: $2\"\n                switch $2 {\n                    break {\n                        break\n                    }\n                    continue {\n                        continue\n                    }\n                    return {\n                        return\n                    }\n                    error {\n                        error \"error message\"\n                    }\n                }\n                error \"should not get here\"\n            }\n        }\n    }\n}\nelog NOTICE \"end of function\"\n$function$;\n-- end --\nDO $$ BEGIN\nCREATE TYPE some-type AS ENUM ('some-val-1', 'some-val-2');\nEXCEPTION\n    WHEN duplicate_object THEN null;\nEND; $$;\n-- end --\nDO $$DECLARE r record;\nBEGIN\n    FOR r IN SELECT table_schema, table_name FROM information_schema.tables\n             WHERE table_type = 'VIEW' AND table_schema = 'public'\n    LOOP\n        EXECUTE 'GRANT ALL ON ' || quote_ident(r.table_schema) || '.' || quote_ident(r.table_name) || ' TO webuser';\n    END LOOP;\nEND$$;\n-- end --\nSELECT * FROM table WHERE name = $$John Doe$$;\n-- end --\nSELECT * FROM table WHERE name = $a1$John Doe$a1$;\n-- end --\nUPDATE table SET description = $$Lorem ipsum dolor sit amet$$ WHERE id = 123;\n-- end --\nINSERT INTO table (name, description) VALUES ($$Jane Smith$$, $$This is Jane's description$$);\n-- end --\nCREATE INDEX index ON table (c);\n-- end --\nCREATE TRIGGER trigger BEFORE INSERT ON table FOR EACH ROW EXECUTE FUNCTION function(params);\n-- end --\nSELECT COUNT(*) FROM table WHERE description ILIKE $$%foo%$$;\n-- end --\nCREATE FUNCTION my_function() RETURNS void AS $$\nBEGIN\n   -- function body here\nEND;\n$$ LANGUAGE plpgsql;\n-- end --\nCREATE OR REPLACE FUNCTION f1(target regclass)\n  RETURNS VOID AS $BEGIN$\nDECLARE\ntable_name TEXT := quote_ident(target :: text);\nBEGIN\nEXECUTE 'alter table ' || table_name || ' add column id serial';\nEND;\n$BEGIN$\nLANGUAGE plpgsql;"
  },
  {
    "path": "sql/migrate/testdata/lex/16_begin_atomic.sql",
    "content": "CREATE FUNCTION functest_S_1(a text, b date) RETURNS boolean\n    LANGUAGE SQL\n    RETURN a = 'abcd' AND b > '2001-01-01';\nCREATE FUNCTION functest_S_2(a text[]) RETURNS int\n    RETURN a[1]::int;\nCREATE FUNCTION functest_S_3() RETURNS boolean\n    RETURN false;\nCREATE FUNCTION functest_S_10(a text, b date) RETURNS boolean\n    LANGUAGE SQL\nBEGIN ATOMIC\nSELECT a = 'abcd' AND b > '2001-01-01';\nEND;\nCREATE FUNCTION functest_S_13() RETURNS boolean\nBEGIN ATOMIC\nSELECT 1;\nSELECT false;\nEND;\nCREATE FUNCTION functest_S_15(x int) RETURNS boolean\n    LANGUAGE SQL\nBEGIN ATOMIC\nselect case when x % 2 = 0 then true else false end; -- tricky parsing\nEND;\nCREATE FUNCTION functest_sri2() RETURNS SETOF int\nLANGUAGE SQL\nSTABLE\nBEGIN ATOMIC\nSELECT * FROM functest3;\nEND;\nCREATE TABLE functest1 (i int);\nCREATE FUNCTION functest_S_16(a int, b int) RETURNS void\n    LANGUAGE SQL\nBEGIN ATOMIC\nINSERT INTO functest1 SELECT a + $2;\nEND;\n\nCREATE FUNCTION functest_S_15(x int) RETURNS boolean\n    LANGUAGE SQL\nBEGIN ATOMIC\nselect case when x % 2 = 0 then true else false end;\nselect case when x % 2 = 0 then true else false end;\nselect case when x % 2 = 0 then true else false end;\nselect case when x % 2 = 0 then true else false end;\nEND;\n\nCREATE FUNCTION \"functest_s_15\" (\"x\" integer) RETURNS boolean LANGUAGE SQL BEGIN ATOMIC\nSELECT\n         CASE\n             WHEN ((x % 2) = 0) THEN true\n             ELSE false\n         END AS \"case\";\nEND;"
  },
  {
    "path": "sql/migrate/testdata/lex/16_begin_atomic.sql.golden",
    "content": "CREATE FUNCTION functest_S_1(a text, b date) RETURNS boolean\n    LANGUAGE SQL\n    RETURN a = 'abcd' AND b > '2001-01-01';\n-- end --\nCREATE FUNCTION functest_S_2(a text[]) RETURNS int\n    RETURN a[1]::int;\n-- end --\nCREATE FUNCTION functest_S_3() RETURNS boolean\n    RETURN false;\n-- end --\nCREATE FUNCTION functest_S_10(a text, b date) RETURNS boolean\n    LANGUAGE SQL\nBEGIN ATOMIC\nSELECT a = 'abcd' AND b > '2001-01-01';\nEND;\n-- end --\nCREATE FUNCTION functest_S_13() RETURNS boolean\nBEGIN ATOMIC\nSELECT 1;\nSELECT false;\nEND;\n-- end --\nCREATE FUNCTION functest_S_15(x int) RETURNS boolean\n    LANGUAGE SQL\nBEGIN ATOMIC\nselect case when x % 2 = 0 then true else false end; -- tricky parsing\nEND;\n-- end --\nCREATE FUNCTION functest_sri2() RETURNS SETOF int\nLANGUAGE SQL\nSTABLE\nBEGIN ATOMIC\nSELECT * FROM functest3;\nEND;\n-- end --\nCREATE TABLE functest1 (i int);\n-- end --\nCREATE FUNCTION functest_S_16(a int, b int) RETURNS void\n    LANGUAGE SQL\nBEGIN ATOMIC\nINSERT INTO functest1 SELECT a + $2;\nEND;\n-- end --\nCREATE FUNCTION functest_S_15(x int) RETURNS boolean\n    LANGUAGE SQL\nBEGIN ATOMIC\nselect case when x % 2 = 0 then true else false end;\nselect case when x % 2 = 0 then true else false end;\nselect case when x % 2 = 0 then true else false end;\nselect case when x % 2 = 0 then true else false end;\nEND;\n-- end --\nCREATE FUNCTION \"functest_s_15\" (\"x\" integer) RETURNS boolean LANGUAGE SQL BEGIN ATOMIC\nSELECT\n         CASE\n             WHEN ((x % 2) = 0) THEN true\n             ELSE false\n         END AS \"case\";\nEND;"
  },
  {
    "path": "sql/migrate/testdata/lex/17_paren.sql",
    "content": "ALTER TABLE ONLY t ADD CONSTRAINT name1 EXCLUDE USING gist (id WITH =, cid WITH -|-);\nALTER TABLE ONLY t\n    ADD CONSTRAINT name2 EXCLUDE USING gist (id WITH =, cid WITH -|-);\nALTER TABLE ONLY t\n    ADD CONSTRAINT name3 EXCLUDE USING gist (id WITH =, cid WITH -|-),\n    ADD CONSTRAINT name4 EXCLUDE USING gist (id WITH =, cid WITH -|-);\n"
  },
  {
    "path": "sql/migrate/testdata/lex/17_paren.sql.golden",
    "content": "ALTER TABLE ONLY t ADD CONSTRAINT name1 EXCLUDE USING gist (id WITH =, cid WITH -|-);\n-- end --\nALTER TABLE ONLY t\n    ADD CONSTRAINT name2 EXCLUDE USING gist (id WITH =, cid WITH -|-);\n-- end --\nALTER TABLE ONLY t\n    ADD CONSTRAINT name3 EXCLUDE USING gist (id WITH =, cid WITH -|-),\n    ADD CONSTRAINT name4 EXCLUDE USING gist (id WITH =, cid WITH -|-);"
  },
  {
    "path": "sql/migrate/testdata/lex/18_pg_expr.sql",
    "content": "-- Comment 1.\nCREATE INDEX \"i\" ON \"s\".\"t\" (((c #>> '{a,b,c}'::text[])));\n\n/*\n Comment 2.\n */\nSELECT name\nFROM company.employees\nWHERE info #>> '{department, name}' = 'Engineering';\n\n/*\n SELECT name\nFROM company.employees\nWHERE info #>> '{contact, email}' = 'alice@company.com';\n */\nSELECT name\nFROM company.employees\nWHERE info #>> '{contact, email}' = 'alice@company.com';\n\n-- Comment 3.\nCREATE INDEX \"idx_emp_department\" ON \"company\".\"employees\" (\n    (info #>> '{department, name}')\n);\n\n/*\n\nCREATE INDEX \"idx_emp_contact\" ON \"company\".\"employees\" (\n    LOWER(info #>> '{contact, email}')\n);\n */\nCREATE INDEX \"idx_emp_contact\" ON \"company\".\"employees\" (\n    LOWER(info #>> '{contact, email}')\n);\n\n/**\n  SELECT\n    info #>> '{department, name}' AS department,\n    COUNT(*) AS emp_count\nFROM company.employees\nGROUP BY info #>> '{department, name}';\n */\nSELECT\n    info #>> '{department, name}' AS department,\n    COUNT(*) AS emp_count\nFROM company.employees\nGROUP BY info #>> '{department, name}';\n\n/**\n  SELECT\n    info #>> '{department, name}' AS department,\n    COUNT(*) AS emp_count\nFROM company.employees\nGROUP BY info #>> '{department, name}';\n */\n/**\n  SELECT\n    info #>> '{department, name}' AS department,\n    COUNT(*) AS emp_count\nFROM company.employees\nGROUP BY info #>> '{department, name}';\n */\nSELECT name\nFROM company.employees\nWHERE (info #>> '{department, name}' = 'Engineering'\n       OR info #>> '{department, location}' = 'Building A')\n  AND info #>> '{contact, email}' LIKE '%@company.com';"
  },
  {
    "path": "sql/migrate/testdata/lex/18_pg_expr.sql.golden",
    "content": "CREATE INDEX \"i\" ON \"s\".\"t\" (((c #>> '{a,b,c}'::text[])));\n-- end --\nSELECT name\nFROM company.employees\nWHERE info #>> '{department, name}' = 'Engineering';\n-- end --\nSELECT name\nFROM company.employees\nWHERE info #>> '{contact, email}' = 'alice@company.com';\n-- end --\nCREATE INDEX \"idx_emp_department\" ON \"company\".\"employees\" (\n    (info #>> '{department, name}')\n);\n-- end --\nCREATE INDEX \"idx_emp_contact\" ON \"company\".\"employees\" (\n    LOWER(info #>> '{contact, email}')\n);\n-- end --\nSELECT\n    info #>> '{department, name}' AS department,\n    COUNT(*) AS emp_count\nFROM company.employees\nGROUP BY info #>> '{department, name}';\n-- end --\nSELECT name\nFROM company.employees\nWHERE (info #>> '{department, name}' = 'Engineering'\n       OR info #>> '{department, location}' = 'Building A')\n  AND info #>> '{contact, email}' LIKE '%@company.com';"
  },
  {
    "path": "sql/migrate/testdata/lex/19_ms_gocmd.sql",
    "content": "go\nSELECT 1\n-- comment here\nGO\nSELECT 2 -- another comment\nGO\nSELECT 3 GO\nGO\nSELECT 4\nGOTO\nSELECT 5\nGO 11\nSELECT 6\nGO"
  },
  {
    "path": "sql/migrate/testdata/lex/19_ms_gocmd.sql.golden",
    "content": "\n-- end --\nSELECT 1\n-- comment here\n-- end --\nSELECT 2 -- another comment\n-- end --\nSELECT 3 GO\n-- end --\nSELECT 4\nGOTO\nSELECT 5\n-- end --\nSELECT 6"
  },
  {
    "path": "sql/migrate/testdata/lex/20_ms_go-delim.sql",
    "content": "-- atlas:delimiter \\nGO\n\ngo\nSELECT 1\n-- comment here\nGO\nSELECT 2 -- another comment\nGO\nSELECT 3 GO\ngO\nSELECT 4\nGOTO -- this command is truncated by delimiter\nSELECT 5\nGO 11\nSELECT 6\nGO"
  },
  {
    "path": "sql/migrate/testdata/lex/20_ms_go-delim.sql.golden",
    "content": "\n-- end --\nSELECT 1\n-- comment here\n-- end --\nSELECT 2 -- another comment\n-- end --\nSELECT 3 GO\n-- end --\nSELECT 4\n-- end --\nTO -- this command is truncated by delimiter\nSELECT 5\n-- end --\nSELECT 6"
  },
  {
    "path": "sql/migrate/testdata/lex/2_mysql.sql",
    "content": "create table t1 (b char(0));\ncreate table t1 (b char(0) not null);\ncreate table if not exists t1 (b char(0) not null);\ncreate table t2 engine=heap select * from t1;\ncreate table t1 (ordid int(8) not null auto_increment, ord  varchar(50) not null, primary key (ord,ordid)) engine=heap;\ncreate table mysqltest.$test1 (a$1 int, $b int, c$ int);\ncreate table t2 (b int) select a as b, a+1 as b from t1;\ncreate table t1 select if('2002'='2002','Y','N');\ncreate table t1 ( k1 varchar(2), k2 int, primary key(k1,k2));\ninsert into t1 values (\"a\", 1), (\"b\", 2);\ncreate table t2\nselect\n    a,\n    ifnull(b,cast(-7                        as signed))   as b,\n    ifnull(c,cast(7                         as unsigned)) as c,\n    ifnull(d,cast('2000-01-01'              as date))     as d,\n    ifnull(e,cast('b'                       as char))     as e,\n    ifnull(f,cast('2000-01-01'              as datetime)) as f,\n    ifnull(g,cast('5:4:3'                   as time))     as g,\n    ifnull(h,cast('yet another binary data' as binary))   as h,\n    addtime(cast('1:0:0' as time),cast('1:0:0' as time))  as dd\nfrom t1;\nCREATE TABLE t1(id varchar(10) NOT NULL PRIMARY KEY, dsc longtext);\nINSERT INTO t1 VALUES ('5000000001', NULL),('5000000003', 'Test'),('5000000004', NULL);\ncreate table t1 (\n    a varchar(112) charset utf8 collate utf8_bin not null,\n    primary key (a)\n) select 'test' as a ;\ncreate table טבלה_של_אריאל\n(\n    כמות int\n);\n\n\n\nCREATE TABLE t1(\n    c1 INT DEFAULT 12 COMMENT 'column1',\n    c2 INT NULL COMMENT 'column2',\n    c3 INT NOT NULL COMMENT 'column3',\n    c4 VARCHAR(255) CHARACTER SET utf8 NOT NULL DEFAULT 'a',\n    c5 VARCHAR(255) COLLATE utf8_unicode_ci NULL DEFAULT 'b',\n    c6 VARCHAR(255))\nCOLLATE latin1_bin;"
  },
  {
    "path": "sql/migrate/testdata/lex/2_mysql.sql.golden",
    "content": "create table t1 (b char(0));\n-- end --\ncreate table t1 (b char(0) not null);\n-- end --\ncreate table if not exists t1 (b char(0) not null);\n-- end --\ncreate table t2 engine=heap select * from t1;\n-- end --\ncreate table t1 (ordid int(8) not null auto_increment, ord  varchar(50) not null, primary key (ord,ordid)) engine=heap;\n-- end --\ncreate table mysqltest.$test1 (a$1 int, $b int, c$ int);\n-- end --\ncreate table t2 (b int) select a as b, a+1 as b from t1;\n-- end --\ncreate table t1 select if('2002'='2002','Y','N');\n-- end --\ncreate table t1 ( k1 varchar(2), k2 int, primary key(k1,k2));\n-- end --\ninsert into t1 values (\"a\", 1), (\"b\", 2);\n-- end --\ncreate table t2\nselect\n    a,\n    ifnull(b,cast(-7                        as signed))   as b,\n    ifnull(c,cast(7                         as unsigned)) as c,\n    ifnull(d,cast('2000-01-01'              as date))     as d,\n    ifnull(e,cast('b'                       as char))     as e,\n    ifnull(f,cast('2000-01-01'              as datetime)) as f,\n    ifnull(g,cast('5:4:3'                   as time))     as g,\n    ifnull(h,cast('yet another binary data' as binary))   as h,\n    addtime(cast('1:0:0' as time),cast('1:0:0' as time))  as dd\nfrom t1;\n-- end --\nCREATE TABLE t1(id varchar(10) NOT NULL PRIMARY KEY, dsc longtext);\n-- end --\nINSERT INTO t1 VALUES ('5000000001', NULL),('5000000003', 'Test'),('5000000004', NULL);\n-- end --\ncreate table t1 (\n    a varchar(112) charset utf8 collate utf8_bin not null,\n    primary key (a)\n) select 'test' as a ;\n-- end --\ncreate table טבלה_של_אריאל\n(\n    כמות int\n);\n-- end --\nCREATE TABLE t1(\n    c1 INT DEFAULT 12 COMMENT 'column1',\n    c2 INT NULL COMMENT 'column2',\n    c3 INT NOT NULL COMMENT 'column3',\n    c4 VARCHAR(255) CHARACTER SET utf8 NOT NULL DEFAULT 'a',\n    c5 VARCHAR(255) COLLATE utf8_unicode_ci NULL DEFAULT 'b',\n    c6 VARCHAR(255))\nCOLLATE latin1_bin;"
  },
  {
    "path": "sql/migrate/testdata/lex/3_delimiter.sql",
    "content": "-- atlas:delimiter \\n\\n\n\nCREATE INDEX i1 ON t1(c1)\n\nCREATE INDEX i2 ON t2(c2)"
  },
  {
    "path": "sql/migrate/testdata/lex/3_delimiter.sql.golden",
    "content": "CREATE INDEX i1 ON t1(c1)\n-- end --\nCREATE INDEX i2 ON t2(c2)"
  },
  {
    "path": "sql/migrate/testdata/lex/4_delimiter.sql",
    "content": "-- atlas:delimiter \\n---\\n\n\nCREATE INDEX i1 ON t1(c1)\n---\nCREATE INDEX i2 ON t2(c2)"
  },
  {
    "path": "sql/migrate/testdata/lex/4_delimiter.sql.golden",
    "content": "CREATE INDEX i1 ON t1(c1)\n-- end --\nCREATE INDEX i2 ON t2(c2)"
  },
  {
    "path": "sql/migrate/testdata/lex/5_delimiter.sql",
    "content": "-- atlas:delimiter \\n-- end --\\n\n\nCREATE DEFINER='boring' PROCEDURE proc ()\n    COMMENT 'ATLAS_DELIMITER'\n    SQL SECURITY INVOKER\n    NOT DETERMINISTIC\n    MODIFIES SQL DATA\nBEGIN\n    UPDATE performance_schema.threads\n    SET instrumented = 'YES'\n    WHERE type = 'BACKGROUND';\n\n    SELECT CONCAT('Enabled ', @rows := ROW_COUNT(), ' background thread', IF(@rows != 1, 's', '')) AS summary;\nEND\n\n-- end --\n\nCALL proc();"
  },
  {
    "path": "sql/migrate/testdata/lex/5_delimiter.sql.golden",
    "content": "CREATE DEFINER='boring' PROCEDURE proc ()\n    COMMENT 'ATLAS_DELIMITER'\n    SQL SECURITY INVOKER\n    NOT DETERMINISTIC\n    MODIFIES SQL DATA\nBEGIN\n    UPDATE performance_schema.threads\n    SET instrumented = 'YES'\n    WHERE type = 'BACKGROUND';\n\n    SELECT CONCAT('Enabled ', @rows := ROW_COUNT(), ' background thread', IF(@rows != 1, 's', '')) AS summary;\nEND\n-- end --\nCALL proc();"
  },
  {
    "path": "sql/migrate/testdata/lex/6_skip_comment.sql",
    "content": "-- comment 1\nCREATE TABLE t1(id int);\n# CREATE TABLE t1(id int);\n\n-- comment 2\n# CREATE TABLE t2(id int);\nCREATE TABLE t2(id int);\n-- comment 3\nCREATE TABLE t3(id int);\n\n# CREATE TABLE t3(id int);\n\n/* comment 4 */\nCREATE TABLE t4(\n    id int\n    /* comment */\n    -- comment\n) ENGINE=InnoDB;\n\n/* comment 5\n*/\nCREATE TABLE t5(\n    id int\n    /* comment */\n    -- comment\n) ENGINE=InnoDB;\n\nSELECT * FROM (\n  SELECT * FROM t1 # comment\n);\n\n# This is a statement's comment.\nSELECT * FROM t2;"
  },
  {
    "path": "sql/migrate/testdata/lex/6_skip_comment.sql.golden",
    "content": "CREATE TABLE t1(id int);\n-- end --\nCREATE TABLE t2(id int);\n-- end --\nCREATE TABLE t3(id int);\n-- end --\nCREATE TABLE t4(\n    id int\n    /* comment */\n    -- comment\n) ENGINE=InnoDB;\n-- end --\nCREATE TABLE t5(\n    id int\n    /* comment */\n    -- comment\n) ENGINE=InnoDB;\n-- end --\nSELECT * FROM (\n  SELECT * FROM t1 # comment\n);\n-- end --\nSELECT * FROM t2;"
  },
  {
    "path": "sql/migrate/testdata/lex/7_delimiter_2n.sql",
    "content": "-- atlas:delimiter \\n\\n\n\nCREATE EXTENSION IF NOT EXISTS unaccent;\n\nCREATE OR REPLACE FUNCTION public.slugify(\n    v TEXT\n) RETURNS TEXT STRICT IMMUTABLE AS $$\nBEGIN\n    RETURN trim(BOTH '-' FROM regexp_replace(lower(unaccent(trim(v))), '[^a-z0-9\\\\-_]+', '-', 'gi'));\nEND;\nLANGUAGE plpgsql;\n\n"
  },
  {
    "path": "sql/migrate/testdata/lex/7_delimiter_2n.sql.golden",
    "content": "CREATE EXTENSION IF NOT EXISTS unaccent;\n-- end --\nCREATE OR REPLACE FUNCTION public.slugify(\n    v TEXT\n) RETURNS TEXT STRICT IMMUTABLE AS $$\nBEGIN\n    RETURN trim(BOTH '-' FROM regexp_replace(lower(unaccent(trim(v))), '[^a-z0-9\\\\-_]+', '-', 'gi'));\nEND;\nLANGUAGE plpgsql;"
  },
  {
    "path": "sql/migrate/testdata/lex/8_delimiter_3n.sql",
    "content": "-- atlas:delimiter \\n\\n\\n\n\nCREATE EXTENSION IF NOT EXISTS unaccent;\n\n\nCREATE OR REPLACE FUNCTION public.slugify(\n    v TEXT\n) RETURNS TEXT STRICT IMMUTABLE AS $$\nBEGIN\n    RETURN trim(BOTH '-' FROM regexp_replace(lower(unaccent(trim(v))), '[^a-z0-9\\\\-_]+', '-', 'gi'));\nEND;\nLANGUAGE plpgsql;\n"
  },
  {
    "path": "sql/migrate/testdata/lex/8_delimiter_3n.sql.golden",
    "content": "CREATE EXTENSION IF NOT EXISTS unaccent;\n-- end --\nCREATE OR REPLACE FUNCTION public.slugify(\n    v TEXT\n) RETURNS TEXT STRICT IMMUTABLE AS $$\nBEGIN\n    RETURN trim(BOTH '-' FROM regexp_replace(lower(unaccent(trim(v))), '[^a-z0-9\\\\-_]+', '-', 'gi'));\nEND;\nLANGUAGE plpgsql;"
  },
  {
    "path": "sql/migrate/testdata/lex/9_delimiter_3n.sql",
    "content": "-- atlas:delimiter \\n\\n\\n\n\nCREATE PROCEDURE dorepeat(p1 INT)\nBEGIN\n    SET @x = 0;\n    REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;\nEND;\n\n\nCALL dorepeat(1000);\n"
  },
  {
    "path": "sql/migrate/testdata/lex/9_delimiter_3n.sql.golden",
    "content": "CREATE PROCEDURE dorepeat(p1 INT)\nBEGIN\n    SET @x = 0;\n    REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;\nEND;\n-- end --\nCALL dorepeat(1000);"
  },
  {
    "path": "sql/migrate/testdata/lexbegintry/1.sql",
    "content": "CREATE PROCEDURE [usp_LogProcessingExample0] (@logId INT) AS\nBEGIN\n    SET NOCOUNT ON;\n\nBEGIN TRY\n        -- Declare a variable for a result\n        DECLARE @ProcessedLogMessage NVARCHAR(200);\n\n        -- Example: Retrieve a message from a log table based on the log ID\nSELECT @ProcessedLogMessage = CONCAT('Log ID: ', @logId, ' processed successfully.')\nFROM LogTable\nWHERE LogId = @logId;\n\n-- Simulate some business logic by updating the log status\nUPDATE LogTable\nSET Status = 'Processed', ProcessedTime = GETDATE()\nWHERE LogId = @logId;\n\n-- Output success message\nPRINT @ProcessedLogMessage;\nEND TRY\nBEGIN CATCH\n        -- Simplified error handling\n        DECLARE @ErrorMsg NVARCHAR(4000) = ERROR_MESSAGE();\n        DECLARE @ErrorLine INT = ERROR_LINE();\n        DECLARE @ErrorSeverity INT = ERROR_SEVERITY();\n\n        -- Log the error in a hypothetical error logging table\nINSERT INTO SystemErrorLog (ErrorMessage, ErrorLine, ErrorSeverity, ErrorTime)\nVALUES (@ErrorMsg, @ErrorLine, @ErrorSeverity, GETDATE());\n\n-- Provide a simplified error output\nPRINT 'An error occurred during log processing. Details have been recorded.';\nEND CATCH\nEND;\n\nCREATE PROCEDURE [usp_LogProcessingExample1] (@logId INT) AS\nBEGIN\n    SET NOCOUNT ON;\n\nBEGIN TRY\n        -- Declare a variable for a result\n        DECLARE @ProcessedLogMessage NVARCHAR(200);\n\n        -- Example: Retrieve a message from a log table based on the log ID\nSELECT @ProcessedLogMessage = CONCAT('Log ID: ', @logId, ' processed successfully.')\nFROM LogTable\nWHERE LogId = @logId;\n\n-- Simulate some business logic by updating the log status\nUPDATE LogTable\nSET Status = 'Processed', ProcessedTime = GETDATE()\nWHERE LogId = @logId;\n\n-- Output success message\nPRINT @ProcessedLogMessage;\nEND TRY\nBEGIN CATCH\n        -- Simplified error handling\n        DECLARE @ErrorMsg NVARCHAR(4000) = ERROR_MESSAGE();\n        DECLARE @ErrorLine INT = ERROR_LINE();\n        DECLARE @ErrorSeverity INT = ERROR_SEVERITY();\n\n        -- Log the error in a hypothetical error logging table\nINSERT INTO SystemErrorLog (ErrorMessage, ErrorLine, ErrorSeverity, ErrorTime)\nVALUES (@ErrorMsg, @ErrorLine, @ErrorSeverity, GETDATE());\n\n-- Provide a simplified error output\nPRINT 'An error occurred during log processing. Details have been recorded.';\nEND CATCH\nEND;\n"
  },
  {
    "path": "sql/migrate/testdata/lexbegintry/1.sql.golden",
    "content": "CREATE PROCEDURE [usp_LogProcessingExample0] (@logId INT) AS\nBEGIN\n    SET NOCOUNT ON;\n\nBEGIN TRY\n        -- Declare a variable for a result\n        DECLARE @ProcessedLogMessage NVARCHAR(200);\n\n        -- Example: Retrieve a message from a log table based on the log ID\nSELECT @ProcessedLogMessage = CONCAT('Log ID: ', @logId, ' processed successfully.')\nFROM LogTable\nWHERE LogId = @logId;\n\n-- Simulate some business logic by updating the log status\nUPDATE LogTable\nSET Status = 'Processed', ProcessedTime = GETDATE()\nWHERE LogId = @logId;\n\n-- Output success message\nPRINT @ProcessedLogMessage;\nEND TRY\nBEGIN CATCH\n        -- Simplified error handling\n        DECLARE @ErrorMsg NVARCHAR(4000) = ERROR_MESSAGE();\n        DECLARE @ErrorLine INT = ERROR_LINE();\n        DECLARE @ErrorSeverity INT = ERROR_SEVERITY();\n\n        -- Log the error in a hypothetical error logging table\nINSERT INTO SystemErrorLog (ErrorMessage, ErrorLine, ErrorSeverity, ErrorTime)\nVALUES (@ErrorMsg, @ErrorLine, @ErrorSeverity, GETDATE());\n\n-- Provide a simplified error output\nPRINT 'An error occurred during log processing. Details have been recorded.';\nEND CATCH\nEND;\n-- end --\nCREATE PROCEDURE [usp_LogProcessingExample1] (@logId INT) AS\nBEGIN\n    SET NOCOUNT ON;\n\nBEGIN TRY\n        -- Declare a variable for a result\n        DECLARE @ProcessedLogMessage NVARCHAR(200);\n\n        -- Example: Retrieve a message from a log table based on the log ID\nSELECT @ProcessedLogMessage = CONCAT('Log ID: ', @logId, ' processed successfully.')\nFROM LogTable\nWHERE LogId = @logId;\n\n-- Simulate some business logic by updating the log status\nUPDATE LogTable\nSET Status = 'Processed', ProcessedTime = GETDATE()\nWHERE LogId = @logId;\n\n-- Output success message\nPRINT @ProcessedLogMessage;\nEND TRY\nBEGIN CATCH\n        -- Simplified error handling\n        DECLARE @ErrorMsg NVARCHAR(4000) = ERROR_MESSAGE();\n        DECLARE @ErrorLine INT = ERROR_LINE();\n        DECLARE @ErrorSeverity INT = ERROR_SEVERITY();\n\n        -- Log the error in a hypothetical error logging table\nINSERT INTO SystemErrorLog (ErrorMessage, ErrorLine, ErrorSeverity, ErrorTime)\nVALUES (@ErrorMsg, @ErrorLine, @ErrorSeverity, GETDATE());\n\n-- Provide a simplified error output\nPRINT 'An error occurred during log processing. Details have been recorded.';\nEND CATCH\nEND;"
  },
  {
    "path": "sql/migrate/testdata/lexescaped/1.my.sql",
    "content": "create table t (c text default '\\\\');\ncreate table t (c text default \"\\\\\");\ncreate table t (c text default \"\\\"\");\ncreate table t (c text default \"\\\"\" + '\\'');\n"
  },
  {
    "path": "sql/migrate/testdata/lexescaped/1.my.sql.golden",
    "content": "create table t (c text default '\\\\');\n-- end --\ncreate table t (c text default \"\\\\\");\n-- end --\ncreate table t (c text default \"\\\"\");\n-- end --\ncreate table t (c text default \"\\\"\" + '\\'');"
  },
  {
    "path": "sql/migrate/testdata/lexescaped/2.pg.sql",
    "content": "create table t1 (c text default '\\');\ncreate table t1 (c text default E'\\\\');\ncreate table t1 (c text default '\\A\\');\ncreate table t1 (c text default e'\\\\A\\\\');"
  },
  {
    "path": "sql/migrate/testdata/lexescaped/2.pg.sql.golden",
    "content": "create table t1 (c text default '\\');\n-- end --\ncreate table t1 (c text default E'\\\\');\n-- end --\ncreate table t1 (c text default '\\A\\');\n-- end --\ncreate table t1 (c text default e'\\\\A\\\\');"
  },
  {
    "path": "sql/migrate/testdata/lexgroup/1_trigger.sql",
    "content": "-- SQLite test cases.\n\nCREATE TRIGGER before_tbl_insert BEFORE INSERT ON tbl BEGIN SELECT CASE\n    WHEN (new.a = 4) THEN RAISE(IGNORE) END;\nEND;\n\nCREATE TRIGGER after_tbl_insert AFTER INSERT ON tbl BEGIN SELECT CASE\n    WHEN (new.a = 1) THEN RAISE(ABORT,    'Trigger abort')\n    WHEN (new.a = 2) THEN RAISE(FAIL,     'Trigger fail')\n    WHEN (new.a = 3) THEN RAISE(ROLLBACK, 'Trigger rollback') END;\nEND;\n\nCREATE TRIGGER after_tbl2_insert AFTER INSERT ON tbl2 BEGIN\n    UPDATE tbl SET c = 10;\n    INSERT INTO tbl2 VALUES (new.a, new.b, new.c);\nEND;\n\nCREATE TABLE t2(x,y,z);\nCREATE TRIGGER t2r1 AFTER INSERT ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r2 BEFORE INSERT ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r3 AFTER UPDATE ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r4 BEFORE UPDATE ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r5 AFTER DELETE ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r6 BEFORE DELETE ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r7 AFTER INSERT ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r8 BEFORE INSERT ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r9 AFTER UPDATE ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r10 BEFORE UPDATE ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r11 AFTER DELETE ON t2 BEGIN SELECT 1; END;\nCREATE TRIGGER t2r12 BEFORE DELETE ON t2 BEGIN SELECT 1; END;\n\ncreate trigger I_test instead of insert on test\n  begin\n    insert into test1 (id,a) values (NEW.id,NEW.a);\n    insert into test2 (id,b) values (NEW.id,NEW.b);\n  end;\n\nCREATE TRIGGER tr AFTER INSERT ON t3 BEGIN\n  INSERT INTO t3 SELECT new.c+1 WHERE new.c<5;\n  INSERT INTO t2 SELECT new.c*10000+xx.a*100+yy.a\n                   FROM t1 AS xx, t1 AS yy\n                  WHERE xx.a IN (1,2,3,4)\n                    AND yy.a IN (2,3,4,5);\nEND;\n\nCREATE TABLE Item(\n   a integer PRIMARY KEY NOT NULL ,\n   b double NULL ,\n   c int NOT NULL DEFAULT 0\n);\nCREATE TABLE Undo(UndoAction TEXT);\nINSERT INTO Item VALUES (1,38205.60865,340);\nCREATE TRIGGER trigItem_UNDO_AD AFTER DELETE ON Item FOR EACH ROW\nBEGIN\n  INSERT INTO Undo SELECT 'INSERT INTO Item (a,b,c) VALUES ('\n   || coalesce(old.a,'NULL') || ',' || quote(old.b) || ',' || old.c || ');';\nEND;\nDELETE FROM Item WHERE a = 1;\nSELECT * FROM Undo;\n\nCREATE TRIGGER transactionTrigger AFTER INSERT ON tbl10 BEGIN\n    SAVEPOINT sp1;\n    INSERT INTO tbl11 VALUES (new.f);\n    ROLLBACK TO sp1;\nEND;\n\nCREATE TRIGGER errorHandlingTrigger AFTER INSERT ON tbl12 BEGIN\n    BEGIN\n        INSERT INTO tbl13 VALUES (new.g);\n        INSERT INTO tbl13 VALUES (new.g);\n    END;\nEND;\n"
  },
  {
    "path": "sql/migrate/testdata/lexgroup/1_trigger.sql.golden",
    "content": "CREATE TRIGGER before_tbl_insert BEFORE INSERT ON tbl BEGIN SELECT CASE\n    WHEN (new.a = 4) THEN RAISE(IGNORE) END;\nEND;\n-- end --\nCREATE TRIGGER after_tbl_insert AFTER INSERT ON tbl BEGIN SELECT CASE\n    WHEN (new.a = 1) THEN RAISE(ABORT,    'Trigger abort')\n    WHEN (new.a = 2) THEN RAISE(FAIL,     'Trigger fail')\n    WHEN (new.a = 3) THEN RAISE(ROLLBACK, 'Trigger rollback') END;\nEND;\n-- end --\nCREATE TRIGGER after_tbl2_insert AFTER INSERT ON tbl2 BEGIN\n    UPDATE tbl SET c = 10;\n    INSERT INTO tbl2 VALUES (new.a, new.b, new.c);\nEND;\n-- end --\nCREATE TABLE t2(x,y,z);\n-- end --\nCREATE TRIGGER t2r1 AFTER INSERT ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r2 BEFORE INSERT ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r3 AFTER UPDATE ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r4 BEFORE UPDATE ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r5 AFTER DELETE ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r6 BEFORE DELETE ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r7 AFTER INSERT ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r8 BEFORE INSERT ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r9 AFTER UPDATE ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r10 BEFORE UPDATE ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r11 AFTER DELETE ON t2 BEGIN SELECT 1; END;\n-- end --\nCREATE TRIGGER t2r12 BEFORE DELETE ON t2 BEGIN SELECT 1; END;\n-- end --\ncreate trigger I_test instead of insert on test\n  begin\n    insert into test1 (id,a) values (NEW.id,NEW.a);\n    insert into test2 (id,b) values (NEW.id,NEW.b);\n  end;\n-- end --\nCREATE TRIGGER tr AFTER INSERT ON t3 BEGIN\n  INSERT INTO t3 SELECT new.c+1 WHERE new.c<5;\n  INSERT INTO t2 SELECT new.c*10000+xx.a*100+yy.a\n                   FROM t1 AS xx, t1 AS yy\n                  WHERE xx.a IN (1,2,3,4)\n                    AND yy.a IN (2,3,4,5);\nEND;\n-- end --\nCREATE TABLE Item(\n   a integer PRIMARY KEY NOT NULL ,\n   b double NULL ,\n   c int NOT NULL DEFAULT 0\n);\n-- end --\nCREATE TABLE Undo(UndoAction TEXT);\n-- end --\nINSERT INTO Item VALUES (1,38205.60865,340);\n-- end --\nCREATE TRIGGER trigItem_UNDO_AD AFTER DELETE ON Item FOR EACH ROW\nBEGIN\n  INSERT INTO Undo SELECT 'INSERT INTO Item (a,b,c) VALUES ('\n   || coalesce(old.a,'NULL') || ',' || quote(old.b) || ',' || old.c || ');';\nEND;\n-- end --\nDELETE FROM Item WHERE a = 1;\n-- end --\nSELECT * FROM Undo;\n-- end --\nCREATE TRIGGER transactionTrigger AFTER INSERT ON tbl10 BEGIN\n    SAVEPOINT sp1;\n    INSERT INTO tbl11 VALUES (new.f);\n    ROLLBACK TO sp1;\nEND;\n-- end --\nCREATE TRIGGER errorHandlingTrigger AFTER INSERT ON tbl12 BEGIN\n    BEGIN\n        INSERT INTO tbl13 VALUES (new.g);\n        INSERT INTO tbl13 VALUES (new.g);\n    END;\nEND;"
  },
  {
    "path": "sql/migrate/testdata/lexgroup/2_function.sql",
    "content": "CREATE PROCEDURE CompProc(IN p INT)\nBEGIN\n    DECLARE v1 INT DEFAULT 0;\n    DECLARE v2 INT;\n    DECLARE d INT DEFAULT FALSE;\n    DECLARE c1 CURSOR FOR SELECT a FROM t1 WHERE b = p;\n    DECLARE CONTINUE HANDLER FOR NOT FOUND SET d = TRUE;\n\n    OPEN c1;\n    rl: LOOP\n        FETCH c1 INTO v2;\n        IF d THEN\n            LEAVE rl;\n        END IF;\n\n        BEGIN\n            IF v2 > 0 THEN\n                UPDATE t2 SET c = c + v2 WHERE d = p;\n            END IF;\n        END;\n    END LOOP;\n    CLOSE c1;\n\n    BEGIN\n        SELECT COUNT(*) INTO v1 FROM t2 WHERE d = p;\n        IF v1 > 100 THEN\n            CALL OtherProc(p);\n        END IF;\n    END;\n\nEND;\n\n\nCREATE FUNCTION CompFunc(eID INT) RETURNS INT\nBEGIN\n    DECLARE ts INT;\n    DECLARE b INT;\n\n    BEGIN\n        SELECT SUM(s) INTO ts FROM sales WHERE e = eID;\n    END;\n\n    BEGIN\n        IF ts > 10000 THEN\n            SET b = 500;\n        ELSEIF ts BETWEEN 5000 AND 10000 THEN\n            SET b = 300;\n        ELSE\n            SET b = 0;\n        END IF;\n    END;\n\n    RETURN b;\nEND;\n\n\nCREATE PROCEDURE CompLogicProc()\nBEGIN\n    DECLARE i INT DEFAULT 1;\n    DECLARE t INT DEFAULT 0;\n\n    sl: WHILE i <= 10 DO\n        BEGIN\n            IF i MOD 2 = 0 THEN\n                SET t = t + i;\n            ELSE\n                BEGIN\n                    IF i MOD 3 = 0 THEN\n                        SET t = t - i;\n                    END IF;\n                END;\n            END IF;\n            SET i = i + 1;\n        END;\n    END WHILE;\n\n    BEGIN\n        IF t < 0 THEN\n            SET t = 0;\n        END IF;\n    END;\n\n    SELECT t;\nEND;\n\n\nCREATE PROCEDURE ff1()\nBEGIN\n    DECLARE v1, v2, v3, i, j INT DEFAULT 0;\n    DECLARE flag INT DEFAULT FALSE;\n    DECLARE cur CURSOR FOR SELECT col1 FROM tableX;\n    DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = TRUE;\n\n    OPEN cur;\n    main_loop: LOOP\n        FETCH cur INTO v1;\n        IF flag THEN\n            LEAVE main_loop;\n        END IF;\n\n        SET i = 1;\n        WHILE i <= 5 DO\n            SET j = 1;\n            REPEAT\n                SET v2 = (SELECT COUNT(*) FROM tableY WHERE col2 = v1 AND col3 = j);\n                IF v2 > 3 THEN\n                    UPDATE tableZ SET col4 = col4 + 1 WHERE col5 = i;\n                END IF;\n                SET j = j + 1;\n            UNTIL j > 3 END REPEAT;\n            SET i = i + 1;\n        END WHILE;\n\n        compound_logic: BEGIN\n            IF v1 < 10 THEN\n                INSERT INTO tableA (colA) VALUES (v1);\n            ELSEIF v1 BETWEEN 10 AND 20 THEN\n                UPDATE tableB SET colB = v1 WHERE colB < v1;\n            ELSE\n                DELETE FROM tableC WHERE colC = v1;\n            END IF;\n        END;\n    END LOOP;\n    CLOSE cur;\nEND;\n\nselect * from t1 where `begin` < 10;\n\ncreate table t2(begin int);\nselect * from t2 where begin < 10;\n\ncreate table t3(begin int, end int);\nselect * from t3 where begin <> end;\n\ncreate table t4(begin int, end int);\nselect * from t4 where begin > end or begin < end or begin = end or begin in (1,2,3) and end not in (1,2,3);\n\ncreate table t5(begin int, end int);\ncreate trigger t5_insert before insert on t5 for each row set new.begin = new.end;\ncreate trigger t5_insert before insert on t5 for each row\nbegin\n    set new.begin = new.end;\nend;\n\n/*\n The \"NEW.begin\" one is not scanned as a \"BEGIN\" because it is\n not a beginning of s statement and there is no \\s before it.\n*/\nCREATE TRIGGER begin1 BEFORE INSERT ON t5\nFOR EACH ROW\nBEGIN\n    SELECT 1;\n    SELECT 1;\n    SET NEW.begin = NEW.end;\nEND;\n\n/*\n The `begin` column is quoted as an identifier as therefore is skipped.\n*/\nCREATE TRIGGER begin2 BEFORE INSERT ON t5\n    FOR EACH ROW\nBEGIN\n    SELECT 1;\n    SELECT 1;\n    SET `begin` = `end`;\nEND;\n\n/*\n An unquoted begin confuses the lexer, and requires using the DELIMITER command.\n*/\n-- Set a special statement delimiter.\nDELIMITER //;\n\nCREATE TRIGGER begin3 BEFORE INSERT ON t5\n    FOR EACH ROW\nBEGIN\n    SELECT 1;\n    SELECT 1;\n    SET begin = end;\nEND //;\n\n-- Unset the special statement delimiter.\nDELIMITER ;\n\n-- issue 2397.\nCREATE OR REPLACE VIEW claims.current_member_view AS\n    SELECT l.member_load_id, n.name_last_or_organization, g.name_given, n.name_middle, n.name_prefix, n.name_suffix, ps.external_plan_sponsor_id, i.member_identification_code, i.date_of_birth, cgop.group_or_policy_number, a.plan_sponsor_name, stat.is_subscriber, stat.relationship_to_subscriber, ed.employment_begin, cd.benefit_begin, cd.benefit_end\n    FROM claims.member_coverage_load mcl\n    LEFT OUTER JOIN claims.member_load l ON mcl.member_load_id = l.member_load_id\n    LEFT OUTER JOIN claims.plan_sponsor_match m ON mcl.coverage_group_or_plan_id = m.coverage_group_or_plan_id\n    LEFT OUTER JOIN claims.plan_sponsor ps ON ps.plan_sponsor_id = m.plan_sponsor_id\n    LEFT OUTER JOIN claims.member_seen ms ON ms.member_seen_id = l.member_seen_id\n    LEFT OUTER JOIN claims.member_identification i ON ms.member_identification_id = i.member_identification_id\n    LEFT OUTER JOIN claims.name n ON n.name_id = ms.name_id\n    LEFT OUTER JOIN claims.name_given g ON n.name_first_id = g.name_given_id\n    LEFT OUTER JOIN claims.eligibility_date ed ON ed.eligibility_date_id = l.eligibility_date_id\n    LEFT OUTER JOIN claims.eligibility_reference r ON r.eligibility_reference_id = l.eligibility_reference_id\n    LEFT OUTER JOIN claims.eligibility_status stat ON stat.eligibility_status_id = l.eligibility_status_id\n    LEFT OUTER JOIN claims.eligibility_admin a ON a.eligibility_admin_id = l.eligibility_admin_id\n    LEFT OUTER JOIN claims.eligibility_submission s ON s.eligibility_submission_id = l.eligibility_submission_id\n    LEFT OUTER JOIN claims.coverage_group_or_plan cgop ON cgop.coverage_group_or_plan_id = mcl.coverage_group_or_plan_id\n    LEFT OUTER JOIN claims.coverage_date cd ON cd.coverage_date_id = mcl.coverage_date_id\n    WHERE benefit_begin < NOW() AND benefit_end > NOW();"
  },
  {
    "path": "sql/migrate/testdata/lexgroup/2_function.sql.golden",
    "content": "CREATE PROCEDURE CompProc(IN p INT)\nBEGIN\n    DECLARE v1 INT DEFAULT 0;\n    DECLARE v2 INT;\n    DECLARE d INT DEFAULT FALSE;\n    DECLARE c1 CURSOR FOR SELECT a FROM t1 WHERE b = p;\n    DECLARE CONTINUE HANDLER FOR NOT FOUND SET d = TRUE;\n\n    OPEN c1;\n    rl: LOOP\n        FETCH c1 INTO v2;\n        IF d THEN\n            LEAVE rl;\n        END IF;\n\n        BEGIN\n            IF v2 > 0 THEN\n                UPDATE t2 SET c = c + v2 WHERE d = p;\n            END IF;\n        END;\n    END LOOP;\n    CLOSE c1;\n\n    BEGIN\n        SELECT COUNT(*) INTO v1 FROM t2 WHERE d = p;\n        IF v1 > 100 THEN\n            CALL OtherProc(p);\n        END IF;\n    END;\n\nEND;\n-- end --\nCREATE FUNCTION CompFunc(eID INT) RETURNS INT\nBEGIN\n    DECLARE ts INT;\n    DECLARE b INT;\n\n    BEGIN\n        SELECT SUM(s) INTO ts FROM sales WHERE e = eID;\n    END;\n\n    BEGIN\n        IF ts > 10000 THEN\n            SET b = 500;\n        ELSEIF ts BETWEEN 5000 AND 10000 THEN\n            SET b = 300;\n        ELSE\n            SET b = 0;\n        END IF;\n    END;\n\n    RETURN b;\nEND;\n-- end --\nCREATE PROCEDURE CompLogicProc()\nBEGIN\n    DECLARE i INT DEFAULT 1;\n    DECLARE t INT DEFAULT 0;\n\n    sl: WHILE i <= 10 DO\n        BEGIN\n            IF i MOD 2 = 0 THEN\n                SET t = t + i;\n            ELSE\n                BEGIN\n                    IF i MOD 3 = 0 THEN\n                        SET t = t - i;\n                    END IF;\n                END;\n            END IF;\n            SET i = i + 1;\n        END;\n    END WHILE;\n\n    BEGIN\n        IF t < 0 THEN\n            SET t = 0;\n        END IF;\n    END;\n\n    SELECT t;\nEND;\n-- end --\nCREATE PROCEDURE ff1()\nBEGIN\n    DECLARE v1, v2, v3, i, j INT DEFAULT 0;\n    DECLARE flag INT DEFAULT FALSE;\n    DECLARE cur CURSOR FOR SELECT col1 FROM tableX;\n    DECLARE CONTINUE HANDLER FOR NOT FOUND SET flag = TRUE;\n\n    OPEN cur;\n    main_loop: LOOP\n        FETCH cur INTO v1;\n        IF flag THEN\n            LEAVE main_loop;\n        END IF;\n\n        SET i = 1;\n        WHILE i <= 5 DO\n            SET j = 1;\n            REPEAT\n                SET v2 = (SELECT COUNT(*) FROM tableY WHERE col2 = v1 AND col3 = j);\n                IF v2 > 3 THEN\n                    UPDATE tableZ SET col4 = col4 + 1 WHERE col5 = i;\n                END IF;\n                SET j = j + 1;\n            UNTIL j > 3 END REPEAT;\n            SET i = i + 1;\n        END WHILE;\n\n        compound_logic: BEGIN\n            IF v1 < 10 THEN\n                INSERT INTO tableA (colA) VALUES (v1);\n            ELSEIF v1 BETWEEN 10 AND 20 THEN\n                UPDATE tableB SET colB = v1 WHERE colB < v1;\n            ELSE\n                DELETE FROM tableC WHERE colC = v1;\n            END IF;\n        END;\n    END LOOP;\n    CLOSE cur;\nEND;\n-- end --\nselect * from t1 where `begin` < 10;\n-- end --\ncreate table t2(begin int);\n-- end --\nselect * from t2 where begin < 10;\n-- end --\ncreate table t3(begin int, end int);\n-- end --\nselect * from t3 where begin <> end;\n-- end --\ncreate table t4(begin int, end int);\n-- end --\nselect * from t4 where begin > end or begin < end or begin = end or begin in (1,2,3) and end not in (1,2,3);\n-- end --\ncreate table t5(begin int, end int);\n-- end --\ncreate trigger t5_insert before insert on t5 for each row set new.begin = new.end;\n-- end --\ncreate trigger t5_insert before insert on t5 for each row\nbegin\n    set new.begin = new.end;\nend;\n-- end --\nCREATE TRIGGER begin1 BEFORE INSERT ON t5\nFOR EACH ROW\nBEGIN\n    SELECT 1;\n    SELECT 1;\n    SET NEW.begin = NEW.end;\nEND;\n-- end --\nCREATE TRIGGER begin2 BEFORE INSERT ON t5\n    FOR EACH ROW\nBEGIN\n    SELECT 1;\n    SELECT 1;\n    SET `begin` = `end`;\nEND;\n-- end --\nCREATE TRIGGER begin3 BEFORE INSERT ON t5\n    FOR EACH ROW\nBEGIN\n    SELECT 1;\n    SELECT 1;\n    SET begin = end;\nEND\n-- end --\nCREATE OR REPLACE VIEW claims.current_member_view AS\n    SELECT l.member_load_id, n.name_last_or_organization, g.name_given, n.name_middle, n.name_prefix, n.name_suffix, ps.external_plan_sponsor_id, i.member_identification_code, i.date_of_birth, cgop.group_or_policy_number, a.plan_sponsor_name, stat.is_subscriber, stat.relationship_to_subscriber, ed.employment_begin, cd.benefit_begin, cd.benefit_end\n    FROM claims.member_coverage_load mcl\n    LEFT OUTER JOIN claims.member_load l ON mcl.member_load_id = l.member_load_id\n    LEFT OUTER JOIN claims.plan_sponsor_match m ON mcl.coverage_group_or_plan_id = m.coverage_group_or_plan_id\n    LEFT OUTER JOIN claims.plan_sponsor ps ON ps.plan_sponsor_id = m.plan_sponsor_id\n    LEFT OUTER JOIN claims.member_seen ms ON ms.member_seen_id = l.member_seen_id\n    LEFT OUTER JOIN claims.member_identification i ON ms.member_identification_id = i.member_identification_id\n    LEFT OUTER JOIN claims.name n ON n.name_id = ms.name_id\n    LEFT OUTER JOIN claims.name_given g ON n.name_first_id = g.name_given_id\n    LEFT OUTER JOIN claims.eligibility_date ed ON ed.eligibility_date_id = l.eligibility_date_id\n    LEFT OUTER JOIN claims.eligibility_reference r ON r.eligibility_reference_id = l.eligibility_reference_id\n    LEFT OUTER JOIN claims.eligibility_status stat ON stat.eligibility_status_id = l.eligibility_status_id\n    LEFT OUTER JOIN claims.eligibility_admin a ON a.eligibility_admin_id = l.eligibility_admin_id\n    LEFT OUTER JOIN claims.eligibility_submission s ON s.eligibility_submission_id = l.eligibility_submission_id\n    LEFT OUTER JOIN claims.coverage_group_or_plan cgop ON cgop.coverage_group_or_plan_id = mcl.coverage_group_or_plan_id\n    LEFT OUTER JOIN claims.coverage_date cd ON cd.coverage_date_id = mcl.coverage_date_id\n    WHERE benefit_begin < NOW() AND benefit_end > NOW();"
  },
  {
    "path": "sql/migrate/testdata/lexgroup/3_delimiter.sql",
    "content": "-- delimiter should not conflict with compound statements scanning.\n\ncreate function `add2` (a int, b int) returns int deterministic no sql return a + b;\ncreate function `add3` (a int, b int, c int) returns int deterministic no sql return a + b + c;\ndelimiter |\n-- error 1418\ncreate function fn1(x int) returns int deterministic\nbegin\n       insert into t1 values (x);\n       return x+2;\nend|\ncreate function fn2(x int) returns int deterministic\nbegin\n       insert into t1 values (x);\n       return x+2;\nend|\ndelimiter ;\ncreate function `add4` (a int, b int, c int, d int) returns int deterministic no sql return a + b + c + d;"
  },
  {
    "path": "sql/migrate/testdata/lexgroup/3_delimiter.sql.golden",
    "content": "create function `add2` (a int, b int) returns int deterministic no sql return a + b;\n-- end --\ncreate function `add3` (a int, b int, c int) returns int deterministic no sql return a + b + c;\n-- end --\ncreate function fn1(x int) returns int deterministic\nbegin\n       insert into t1 values (x);\n       return x+2;\nend\n-- end --\ncreate function fn2(x int) returns int deterministic\nbegin\n       insert into t1 values (x);\n       return x+2;\nend\n-- end --\ncreate function `add4` (a int, b int, c int, d int) returns int deterministic no sql return a + b + c + d;"
  },
  {
    "path": "sql/migrate/testdata/migrate/1_initial.down.sql",
    "content": "DROP TABLE IF EXISTS t;"
  },
  {
    "path": "sql/migrate/testdata/migrate/1_initial.up.sql",
    "content": "CREATE TABLE t(c int);"
  },
  {
    "path": "sql/migrate/testdata/migrate/atlas.sum",
    "content": "h1:M74RrNK69S2pj6C541LR1ew5O32/i0WoyNgsJmyuiUk=\n1_initial.down.sql h1:0zypK43rgPbgvVUgVJABGN25VgM1QSeU+LJDBb8cEQI=\n1_initial.up.sql h1:hFhs5XhRml4KTWGF5td6h1s7xNqAFnaEBbC5Y/NF7i4=\n"
  },
  {
    "path": "sql/migrate/testdata/migrate/sub/1.a_sub.up.sql",
    "content": "-- create table \"t_sub\"\nCREATE TABLE t_sub(c int);\n-- add c1 column\nALTER TABLE t_sub ADD c1 int;"
  },
  {
    "path": "sql/migrate/testdata/migrate/sub/2.10.x-20_description.sql",
    "content": "-- add c2 column\nALTER TABLE t_sub ADD c2 int;"
  },
  {
    "path": "sql/migrate/testdata/migrate/sub/3_partly.sql",
    "content": "-- add c3 column\nALTER TABLE t_sub ADD c3 int;\n-- add c4 column\nALTER TABLE t_sub ADD c4 int;"
  },
  {
    "path": "sql/migrate/testdata/migrate/sub/atlas.sum",
    "content": "h1:VpH77zWOBMwX5QhvnQo0XQvXCrOYZg4h1o0XlJTQnl0=\n1.a_sub.up.sql h1:nXyZR020M/mH7LxkoTkJr7BcQkipVg90imQ9I4595dw=\n2.10.x-20_description.sql h1:wQB3Vh3PHVXQg9OD3Gn7TBxbZN3r1Qb7TtAE1g3q9mQ=\n3_partly.sql h1:lHlMz6mEvBfvjry5lFXjs2vi6Et9xb9CWicaOXD42Qc=\n"
  },
  {
    "path": "sql/migrate/testdata/partial-checkpoint/1_first.sql",
    "content": "create table `tbl_1` (`col` int);\n"
  },
  {
    "path": "sql/migrate/testdata/partial-checkpoint/2_second.sql",
    "content": "create table `tbl_2` (`col` int);\n"
  },
  {
    "path": "sql/migrate/testdata/partial-checkpoint/3_checkpoint.sql",
    "content": "-- atlas:checkpoint\n\nCREATE TABLE `tbl_1` (`col` int);\nCREATE TABLE `tbl_2` (`col` int);\n"
  },
  {
    "path": "sql/migrate/testdata/partial-checkpoint/4_fourth.sql",
    "content": "create table `tbl_3` (`col` int);\n"
  },
  {
    "path": "sql/migrate/testdata/partial-checkpoint/5_checkpoint.sql",
    "content": "-- atlas:checkpoint\n\nCREATE TABLE `tbl_1` (`col` int);\nCREATE TABLE `tbl_2` (`col` int);\ncreate table `tbl_3` (`col` int);\n"
  },
  {
    "path": "sql/migrate/testdata/partial-checkpoint/6_sixth.sql",
    "content": "CREATE TABLE `tbl_4` (`col` int);\n"
  },
  {
    "path": "sql/migrate/testdata/partial-checkpoint/atlas.sum",
    "content": "h1:POfbsH2G2GIXAZQ2CdPa5ufTxcLpcnperz/gX0Vw6Uk=\n1_first.sql h1:uJ2MyyeTqXx4rCqtRMQAvRrfsvdwmvsZ3LcadVvCdOc=\n2_second.sql h1:TLO00GtsqSi8o0ySoaofBqxemrElL8fHOs3IRnqYvB8=\n3_checkpoint.sql h1:LR4UjDYVtrRuHLN5GQwLAYnXrSf/iO70psY8hTmLmjw=\n4_fourth.sql h1:QvaneqKxg+3R+zNzCP/wW43XkECdHkUwEpxJKPICEP8=\n5_checkpoint.sql h1:syyuaJb/hoMRO7MJlv4AMhYqMCoSb8ZgcHENO8RqN3I=\n6_sixth.sql h1:JNhpyBtH7XKqGBNRHQ+AvM9IDpO08C3G/swWPHfLkfw=\n"
  },
  {
    "path": "sql/migrate/testdata/sqlserver/1_return_table.sql",
    "content": "CREATE FUNCTION [f2](@a as INT, @b as INT = 1)\nRETURNS TABLE\nAS RETURN SELECT @a as [a], @b as [b], (@a+@b)*2 as [p], @a*@b as [s];\nCREATE FUNCTION [f3] (@a int, @b int = 1) RETURNS @t1 TABLE ([c1] int NOT NULL, [c2] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [c3] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS DEFAULT N'G' NULL, [c4] int NOT NULL, PRIMARY KEY CLUSTERED ([c1] ASC), INDEX [idx] NONCLUSTERED ([c2] ASC), UNIQUE NONCLUSTERED ([c2] ASC, [c3] DESC), UNIQUE NONCLUSTERED ([c3] DESC, [c4] ASC), CHECK ([c4]>(0))) AS BEGIN \n  INSERT @t1\n  SELECT 1 AS [c1], 'A' AS [c2], NULL AS [c3], @a * @a + @b AS [c4];\nRETURN\nEND\n"
  },
  {
    "path": "sql/migrate/testdata/sqlserver/1_return_table.sql.golden",
    "content": "CREATE FUNCTION [f2](@a as INT, @b as INT = 1)\nRETURNS TABLE\nAS RETURN SELECT @a as [a], @b as [b], (@a+@b)*2 as [p], @a*@b as [s];\n-- end --\nCREATE FUNCTION [f3] (@a int, @b int = 1) RETURNS @t1 TABLE ([c1] int NOT NULL, [c2] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [c3] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS DEFAULT N'G' NULL, [c4] int NOT NULL, PRIMARY KEY CLUSTERED ([c1] ASC), INDEX [idx] NONCLUSTERED ([c2] ASC), UNIQUE NONCLUSTERED ([c2] ASC, [c3] DESC), UNIQUE NONCLUSTERED ([c3] DESC, [c4] ASC), CHECK ([c4]>(0))) AS BEGIN \n  INSERT @t1\n  SELECT 1 AS [c1], 'A' AS [c2], NULL AS [c3], @a * @a + @b AS [c4];\nRETURN\nEND"
  },
  {
    "path": "sql/migrate/testdata/sqlserver/2_function.sql",
    "content": "-- atlas:delimiter \\nGO\n\nCREATE FUNCTION [f3] (@a int, @b int = 1) RETURNS @t1 TABLE ([c1] int NOT NULL, [c2] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [c3] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS DEFAULT N'G' NULL, [c4] int NOT NULL, PRIMARY KEY CLUSTERED ([c1] ASC), INDEX [idx] NONCLUSTERED ([c2] ASC), UNIQUE NONCLUSTERED ([c2] ASC, [c3] DESC), UNIQUE NONCLUSTERED ([c3] DESC, [c4] ASC), CHECK ([c4]>(0))) AS BEGIN\n  INSERT @t1\n  SELECT 1 AS [c1], 'A' AS [c2], NULL AS [c3], @a * @a + @b AS [c4];\nRETURN\nEND\nGO\nCREATE FUNCTION [f3] (@a int, @b int = 1) RETURNS @t1 TABLE ([c1] int NOT NULL, [c2] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [c3] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS DEFAULT N'G' NULL, [c4] int NOT NULL, PRIMARY KEY CLUSTERED ([c1] ASC), INDEX [idx] NONCLUSTERED ([c2] ASC), UNIQUE NONCLUSTERED ([c2] ASC, [c3] DESC), UNIQUE NONCLUSTERED ([c3] DESC, [c4] ASC), CHECK ([c4]>(0))) AS BEGIN\n  INSERT @t1\n  SELECT 1 AS [c1], 'A' AS [c2], NULL AS [c3], @a * @a + @b AS [c4];\nRETURN\nEND\nGO\nCREATE FUNCTION [f3] (@a int, @b int = 1) RETURNS @t1 TABLE ([c1] int NOT NULL, [c2] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [c3] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS DEFAULT N'G' NULL, [c4] int NOT NULL, PRIMARY KEY CLUSTERED ([c1] ASC), INDEX [idx] NONCLUSTERED ([c2] ASC), UNIQUE NONCLUSTERED ([c2] ASC, [c3] DESC), UNIQUE NONCLUSTERED ([c3] DESC, [c4] ASC), CHECK ([c4]>(0))) AS BEGIN\n  INSERT @t1\n  SELECT 1 AS [c1], 'A' AS [c2], NULL AS [c3], @a * @a + @b AS [c4];\nRETURN\nEND"
  },
  {
    "path": "sql/migrate/testdata/sqlserver/2_function.sql.golden",
    "content": "CREATE FUNCTION [f3] (@a int, @b int = 1) RETURNS @t1 TABLE ([c1] int NOT NULL, [c2] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [c3] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS DEFAULT N'G' NULL, [c4] int NOT NULL, PRIMARY KEY CLUSTERED ([c1] ASC), INDEX [idx] NONCLUSTERED ([c2] ASC), UNIQUE NONCLUSTERED ([c2] ASC, [c3] DESC), UNIQUE NONCLUSTERED ([c3] DESC, [c4] ASC), CHECK ([c4]>(0))) AS BEGIN\n  INSERT @t1\n  SELECT 1 AS [c1], 'A' AS [c2], NULL AS [c3], @a * @a + @b AS [c4];\nRETURN\nEND\n-- end --\nCREATE FUNCTION [f3] (@a int, @b int = 1) RETURNS @t1 TABLE ([c1] int NOT NULL, [c2] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [c3] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS DEFAULT N'G' NULL, [c4] int NOT NULL, PRIMARY KEY CLUSTERED ([c1] ASC), INDEX [idx] NONCLUSTERED ([c2] ASC), UNIQUE NONCLUSTERED ([c2] ASC, [c3] DESC), UNIQUE NONCLUSTERED ([c3] DESC, [c4] ASC), CHECK ([c4]>(0))) AS BEGIN\n  INSERT @t1\n  SELECT 1 AS [c1], 'A' AS [c2], NULL AS [c3], @a * @a + @b AS [c4];\nRETURN\nEND\n-- end --\nCREATE FUNCTION [f3] (@a int, @b int = 1) RETURNS @t1 TABLE ([c1] int NOT NULL, [c2] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [c3] nvarchar(255) COLLATE SQL_Latin1_General_CP1_CI_AS DEFAULT N'G' NULL, [c4] int NOT NULL, PRIMARY KEY CLUSTERED ([c1] ASC), INDEX [idx] NONCLUSTERED ([c2] ASC), UNIQUE NONCLUSTERED ([c2] ASC, [c3] DESC), UNIQUE NONCLUSTERED ([c3] DESC, [c4] ASC), CHECK ([c4]>(0))) AS BEGIN\n  INSERT @t1\n  SELECT 1 AS [c1], 'A' AS [c2], NULL AS [c3], @a * @a + @b AS [c4];\nRETURN\nEND"
  },
  {
    "path": "sql/mysql/convert.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage mysql\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// FormatType converts schema type to its column form in the database.\n// An error is returned if the type cannot be recognized.\nfunc FormatType(t schema.Type) (string, error) {\n\tvar f string\n\tswitch t := t.(type) {\n\tcase *BitType:\n\t\tf = strings.ToLower(t.T)\n\t\tif t.Size > 1 {\n\t\t\t// The default size is 1. Thus, both\n\t\t\t// BIT and BIT(1) are formatted as bit.\n\t\t\tf += fmt.Sprintf(\"(%d)\", t.Size)\n\t\t}\n\tcase *schema.BoolType:\n\t\t// Map all flavors to a single form.\n\t\tswitch f = strings.ToLower(t.T); f {\n\t\tcase TypeBool, TypeBoolean, TypeTinyInt, \"tinyint(1)\":\n\t\t\tf = TypeBool\n\t\t}\n\tcase *schema.BinaryType:\n\t\tf = strings.ToLower(t.T)\n\t\t// Accept 0 as a valid size, and avoid appending the default size of type BINARY.\n\t\tif f == TypeVarBinary && t.Size != nil || f == TypeBinary && t.Size != nil && *t.Size != 1 {\n\t\t\tf = fmt.Sprintf(\"%s(%d)\", f, *t.Size)\n\t\t}\n\tcase *schema.DecimalType:\n\t\tif f = strings.ToLower(t.T); f != TypeDecimal && f != TypeNumeric {\n\t\t\treturn \"\", fmt.Errorf(\"unexpected decimal type: %q\", t.T)\n\t\t}\n\t\tswitch p, s := t.Precision, t.Scale; {\n\t\tcase p < 0 || s < 0:\n\t\t\treturn \"\", fmt.Errorf(\"decimal type must have precision > 0 and scale >= 0: %d, %d\", p, s)\n\t\tcase p < s:\n\t\t\treturn \"\", fmt.Errorf(\"decimal type must have precision >= scale: %d < %d\", p, s)\n\t\tcase p == 0 && s == 0:\n\t\t\t// The default value for precision is 10 (i.e. decimal(0,0) = decimal(10)).\n\t\t\tp = 10\n\t\t\tfallthrough\n\t\tcase s == 0:\n\t\t\t// In standard SQL, the syntax DECIMAL(M) is equivalent to DECIMAL(M,0),\n\t\t\tf = fmt.Sprintf(\"decimal(%d)\", p)\n\t\tdefault:\n\t\t\tf = fmt.Sprintf(\"decimal(%d,%d)\", p, s)\n\t\t}\n\t\tif t.Unsigned {\n\t\t\tf += \" unsigned\"\n\t\t}\n\tcase *schema.EnumType:\n\t\tf = fmt.Sprintf(\"enum(%s)\", formatValues(t.Values))\n\tcase *schema.FloatType:\n\t\tf = strings.ToLower(t.T)\n\t\t// FLOAT with precision > 24, become DOUBLE.\n\t\t// Also, REAL is a synonym for DOUBLE (if REAL_AS_FLOAT was not set).\n\t\tif f == TypeFloat && t.Precision > 24 || f == TypeReal {\n\t\t\tf = TypeDouble\n\t\t}\n\t\tif t.Unsigned {\n\t\t\tf += \" unsigned\"\n\t\t}\n\tcase *schema.IntegerType:\n\t\tf = strings.ToLower(t.T)\n\t\tif t.Unsigned {\n\t\t\tf += \" unsigned\"\n\t\t}\n\tcase *schema.JSONType:\n\t\tf = strings.ToLower(t.T)\n\tcase *SetType:\n\t\tf = fmt.Sprintf(\"set(%s)\", formatValues(t.Values))\n\tcase *schema.StringType:\n\t\tf = strings.ToLower(t.T)\n\t\tswitch f {\n\t\tcase TypeChar:\n\t\t\t// Not a single char.\n\t\t\tif t.Size > 0 {\n\t\t\t\tf += fmt.Sprintf(\"(%d)\", t.Size)\n\t\t\t}\n\t\tcase TypeVarchar:\n\t\t\t// Zero is also a valid length.\n\t\t\tf = fmt.Sprintf(\"varchar(%d)\", t.Size)\n\t\t}\n\tcase *schema.SpatialType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.TimeType:\n\t\tf = strings.ToLower(t.T)\n\t\tif p := t.Precision; p != nil && *p > 0 {\n\t\t\tf = fmt.Sprintf(\"%s(%d)\", f, *p)\n\t\t}\n\tcase *schema.UUIDType:\n\t\tf = strings.ToLower(t.T)\n\tcase *NetworkType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.UnsupportedType:\n\t\t// Do not accept unsupported types as we should cover all cases.\n\t\treturn \"\", fmt.Errorf(\"unsupported type %q\", t.T)\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"invalid schema type %T\", t)\n\t}\n\treturn f, nil\n}\n\n// ParseType returns the schema.Type value represented by the given raw type.\n// The raw value is expected to follow the format in MySQL information schema.\nfunc ParseType(raw string) (schema.Type, error) {\n\tparts, size, unsigned, err := parseColumn(raw)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch t := parts[0]; t {\n\tcase TypeBit:\n\t\treturn &BitType{\n\t\t\tT:    t,\n\t\t\tSize: size,\n\t\t}, nil\n\t// bool and booleans are synonyms for\n\t// tinyint with display-width set to 1.\n\tcase TypeBool, TypeBoolean:\n\t\treturn &schema.BoolType{\n\t\t\tT: TypeBool,\n\t\t}, nil\n\tcase TypeTinyInt, TypeSmallInt, TypeMediumInt, TypeInt, TypeBigInt:\n\t\tif size == 1 {\n\t\t\treturn &schema.BoolType{\n\t\t\t\tT: TypeBool,\n\t\t\t}, nil\n\t\t}\n\t\t// For integer types, the size represents the display width and does not\n\t\t// constrain the range of values that can be stored in the column.\n\t\t// The storage byte-size is inferred from the type name (i.e TINYINT takes\n\t\t// a single byte).\n\t\tft := &schema.IntegerType{\n\t\t\tT:        t,\n\t\t\tUnsigned: unsigned,\n\t\t}\n\t\tif attr := parts[len(parts)-1]; attr == \"zerofill\" && size != 0 {\n\t\t\tft.Attrs = []schema.Attr{\n\t\t\t\t&DisplayWidth{\n\t\t\t\t\tN: size,\n\t\t\t\t},\n\t\t\t\t&ZeroFill{\n\t\t\t\t\tA: attr,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t\treturn ft, nil\n\tcase TypeNumeric, TypeDecimal:\n\t\tdt := &schema.DecimalType{\n\t\t\tT:        t,\n\t\t\tUnsigned: unsigned,\n\t\t}\n\t\tif len(parts) > 1 && parts[1] != \"unsigned\" {\n\t\t\tif dt.Precision, err = strconv.Atoi(parts[1]); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse decimal precision %q\", parts[1])\n\t\t\t}\n\t\t}\n\t\tif len(parts) > 2 && parts[2] != \"unsigned\" {\n\t\t\tif dt.Scale, err = strconv.Atoi(parts[2]); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse scale %q\", parts[1])\n\t\t\t}\n\t\t}\n\t\treturn dt, nil\n\tcase TypeFloat, TypeDouble, TypeReal:\n\t\tft := &schema.FloatType{\n\t\t\tT:        t,\n\t\t\tUnsigned: unsigned,\n\t\t}\n\t\tif len(parts) > 1 && parts[1] != \"unsigned\" {\n\t\t\tif ft.Precision, err = strconv.Atoi(parts[1]); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse double precision %q\", parts[1])\n\t\t\t}\n\t\t}\n\t\treturn ft, nil\n\tcase TypeBinary, TypeVarBinary:\n\t\tbt := &schema.BinaryType{T: t}\n\t\tif len(parts) > 1 {\n\t\t\tbt.Size = &size\n\t\t}\n\t\treturn bt, nil\n\tcase TypeTinyBlob, TypeMediumBlob, TypeBlob, TypeLongBlob:\n\t\treturn &schema.BinaryType{\n\t\t\tT: t,\n\t\t}, nil\n\tcase TypeChar, TypeVarchar:\n\t\treturn &schema.StringType{\n\t\t\tT:    t,\n\t\t\tSize: size,\n\t\t}, nil\n\tcase TypeTinyText, TypeMediumText, TypeText, TypeLongText:\n\t\treturn &schema.StringType{\n\t\t\tT: t,\n\t\t}, nil\n\tcase TypeEnum, TypeSet:\n\t\t// Parse the enum values according to the MySQL format.\n\t\t// github.com/mysql/mysql-server/blob/8.0/sql/field.cc#Field_enum::sql_type\n\t\trv := strings.TrimSuffix(strings.TrimPrefix(raw, t+\"(\"), \")\")\n\t\tif rv == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"unexpected enum type: %q\", raw)\n\t\t}\n\t\tvalues := strings.Split(rv, \"','\")\n\t\tfor i := range values {\n\t\t\tvalues[i] = strings.Trim(values[i], \"'\")\n\t\t}\n\t\tif t == TypeEnum {\n\t\t\treturn &schema.EnumType{\n\t\t\t\tT:      TypeEnum,\n\t\t\t\tValues: values,\n\t\t\t}, nil\n\t\t}\n\t\treturn &SetType{\n\t\t\tValues: values,\n\t\t}, nil\n\tcase TypeDate, TypeDateTime, TypeTime, TypeTimestamp, TypeYear:\n\t\ttt := &schema.TimeType{\n\t\t\tT: t,\n\t\t}\n\t\tif len(parts) > 1 {\n\t\t\tp, err := strconv.Atoi(parts[1])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse timestamp precision %q\", parts[1])\n\t\t\t}\n\t\t\ttt.Precision = &p\n\t\t}\n\t\treturn tt, nil\n\tcase TypeJSON:\n\t\treturn &schema.JSONType{\n\t\t\tT: t,\n\t\t}, nil\n\tcase TypePoint, TypeMultiPoint, TypeLineString, TypeMultiLineString, TypePolygon, TypeMultiPolygon, TypeGeometry, TypeGeoCollection, TypeGeometryCollection:\n\t\treturn &schema.SpatialType{\n\t\t\tT: t,\n\t\t}, nil\n\tcase TypeUUID:\n\t\treturn &schema.UUIDType{\n\t\t\tT: t,\n\t\t}, nil\n\tcase TypeInet4, TypeInet6:\n\t\treturn &NetworkType{\n\t\t\tT: t,\n\t\t}, nil\n\tdefault:\n\t\treturn &schema.UnsupportedType{\n\t\t\tT: t,\n\t\t}, nil\n\t}\n}\n\n// formatValues formats ENUM and SET values.\nfunc formatValues(vs []string) string {\n\tvalues := make([]string, len(vs))\n\tfor i := range vs {\n\t\tvalues[i] = vs[i]\n\t\tif !sqlx.IsQuoted(values[i], '\"', '\\'') {\n\t\t\tvalues[i] = \"'\" + values[i] + \"'\"\n\t\t}\n\t}\n\treturn strings.Join(values, \",\")\n}\n"
  },
  {
    "path": "sql/mysql/diff_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysql\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// DefaultDiff provides basic diffing capabilities for MySQL dialects.\n// Note, it is recommended to call Open, create a new Driver and use its\n// Differ when a database connection is available.\nvar DefaultDiff schema.Differ = &sqlx.Diff{DiffDriver: &diff{conn: noConn}}\n\n// A diff provides a MySQL implementation for sqlx.DiffDriver.\ntype diff struct {\n\t*conn\n\t// charset to collation mapping.\n\t// See, internal directory.\n\tch2co, co2ch struct {\n\t\tsync.Once\n\t\tv   map[string]string\n\t\terr error\n\t}\n}\n\n// SupportChange reports if the change is supported by the differ.\nfunc (*diff) SupportChange(c schema.Change) bool {\n\tswitch c.(type) {\n\tcase *schema.RenameConstraint:\n\t\treturn false\n\t}\n\treturn true\n}\n\n// SchemaAttrDiff returns a changeset for migrating schema attributes from one state to the other.\nfunc (d *diff) SchemaAttrDiff(from, to *schema.Schema) []schema.Change {\n\tvar (\n\t\ttopAttr []schema.Attr\n\t\tchanges []schema.Change\n\t)\n\tif from.Realm != nil {\n\t\ttopAttr = from.Realm.Attrs\n\t}\n\t// Charset change.\n\tif change := d.charsetChange(from.Attrs, topAttr, to.Attrs); change != noChange {\n\t\tchanges = append(changes, change)\n\t}\n\t// Collation change.\n\tif change := d.collationChange(from.Attrs, topAttr, to.Attrs); change != noChange {\n\t\tchanges = append(changes, change)\n\t}\n\treturn changes\n}\n\n// RealmObjectDiff returns a changeset for migrating realm (database) objects\n// from one state to the other. For example, adding extensions or users.\nfunc (*diff) RealmObjectDiff(_, _ *schema.Realm) ([]schema.Change, error) {\n\treturn nil, nil\n}\n\n// SchemaObjectDiff returns a changeset for migrating schema objects from\n// one state to the other.\nfunc (*diff) SchemaObjectDiff(_, _ *schema.Schema, _ *schema.DiffOptions) ([]schema.Change, error) {\n\treturn nil, nil\n}\n\n// TableAttrDiff returns a changeset for migrating table attributes from one state to the other.\nfunc (d *diff) TableAttrDiff(from, to *schema.Table, opts *schema.DiffOptions) ([]schema.Change, error) {\n\tvar changes []schema.Change\n\tif change := d.autoIncChange(from.Attrs, to.Attrs); change != noChange {\n\t\tchanges = append(changes, change)\n\t}\n\tif change := sqlx.CommentDiff(from.Attrs, to.Attrs); change != nil {\n\t\tchanges = append(changes, change)\n\t}\n\tif change := d.charsetChange(from.Attrs, from.Schema.Attrs, to.Attrs); change != noChange {\n\t\tchanges = append(changes, change)\n\t}\n\tif change := d.collationChange(from.Attrs, from.Schema.Attrs, to.Attrs); change != noChange {\n\t\tchanges = append(changes, change)\n\t}\n\tif change := d.engineChange(from.Attrs, to.Attrs); change != noChange {\n\t\tchanges = append(changes, change)\n\t}\n\tif change := d.systemVerChange(from.Attrs, to.Attrs); change != noChange {\n\t\tchanges = append(changes, change)\n\t}\n\tif !d.SupportsCheck() && sqlx.Has(to.Attrs, &schema.Check{}) {\n\t\treturn nil, fmt.Errorf(\"version %q does not support CHECK constraints\", d.V)\n\t}\n\t// For MariaDB, we skip JSON CHECK constraints that were created by the databases,\n\t// or by Atlas for older versions. These CHECK constraints (inlined on the columns)\n\t// also cannot be dropped using \"DROP CONSTRAINTS\", but can be modified and dropped\n\t// using \"MODIFY COLUMN\".\n\tvar checks []schema.Change\n\tfor _, c := range sqlx.CheckDiffMode(from, to, opts.Mode, func(c1, c2 *schema.Check) bool {\n\t\treturn enforced(c1.Attrs) == enforced(c2.Attrs)\n\t}) {\n\t\tdrop, ok := c.(*schema.DropCheck)\n\t\tif !ok || !strings.HasPrefix(drop.C.Expr, \"json_valid\") {\n\t\t\tchecks = append(checks, c)\n\t\t\tcontinue\n\t\t}\n\t\t// Generated CHECK have the form of \"json_valid(`<column>`)\"\n\t\t// and named as the column.\n\t\tif _, ok := to.Column(drop.C.Name); !ok {\n\t\t\tchecks = append(checks, c)\n\t\t}\n\t}\n\treturn append(changes, checks...), nil\n}\n\n// ColumnChange returns the schema changes (if any) for migrating one column to the other.\nfunc (d *diff) ColumnChange(fromT *schema.Table, from, to *schema.Column, _ *schema.DiffOptions) (schema.Change, error) {\n\tchange := sqlx.CommentChange(from.Attrs, to.Attrs)\n\tif from.Type.Null != to.Type.Null {\n\t\tchange |= schema.ChangeNull\n\t}\n\tchanged, err := d.typeChanged(from, to)\n\tif err != nil {\n\t\treturn sqlx.NoChange, err\n\t}\n\tif changed {\n\t\tchange |= schema.ChangeType\n\t}\n\tif changed, err = d.defaultChanged(from, to); err != nil {\n\t\treturn sqlx.NoChange, err\n\t}\n\tif changed {\n\t\tchange |= schema.ChangeDefault\n\t}\n\tif changed, err = d.generatedChanged(from, to); err != nil {\n\t\treturn sqlx.NoChange, err\n\t}\n\tif changed {\n\t\tchange |= schema.ChangeGenerated\n\t}\n\tif changed, err = d.columnCharsetChanged(fromT, from, to); err != nil {\n\t\treturn sqlx.NoChange, err\n\t}\n\tif changed {\n\t\tchange |= schema.ChangeCharset\n\t}\n\tif changed, err = d.columnCollateChanged(fromT, from, to); err != nil {\n\t\treturn sqlx.NoChange, err\n\t}\n\tif changed {\n\t\tchange |= schema.ChangeCollate\n\t}\n\tif change.Is(schema.NoChange) {\n\t\treturn sqlx.NoChange, nil\n\t}\n\treturn &schema.ModifyColumn{\n\t\tChange: change,\n\t\tFrom:   from,\n\t\tTo:     to,\n\t}, nil\n}\n\n// IsGeneratedIndexName reports if the index name was generated by the database.\nfunc (d *diff) IsGeneratedIndexName(_ *schema.Table, idx *schema.Index) bool {\n\t// Auto-generated index names for functional/expression indexes. See.\n\t// mysql-server/sql/sql_table.cc#add_functional_index_to_create_list\n\tconst f = \"functional_index\"\n\tswitch {\n\tcase d.SupportsIndexExpr() && idx.Name == f:\n\t\treturn true\n\tcase d.SupportsIndexExpr() && strings.HasPrefix(idx.Name+\"_\", f):\n\t\ti, err := strconv.ParseInt(strings.TrimLeft(idx.Name, idx.Name+\"_\"), 10, 64)\n\t\treturn err == nil && i > 1\n\tcase len(idx.Parts) == 0 || idx.Parts[0].C == nil:\n\t\treturn false\n\t}\n\t// Unnamed INDEX or UNIQUE constraints are named by\n\t// the first index-part (as column or part of it).\n\t// For example, \"c\", \"c_2\", \"c_3\", etc.\n\tswitch name := idx.Parts[0].C.Name; {\n\tcase idx.Name == name:\n\t\treturn true\n\tcase strings.HasPrefix(idx.Name, name+\"_\"):\n\t\ti, err := strconv.ParseInt(strings.TrimPrefix(idx.Name, name+\"_\"), 10, 64)\n\t\treturn err == nil && i > 1\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// IndexAttrChanged reports if the index attributes were changed.\nfunc (*diff) IndexAttrChanged(from, to []schema.Attr) bool {\n\tif indexType(from).T != indexType(to).T {\n\t\treturn true\n\t}\n\tvar (\n\t\tfromP, toP     IndexParser\n\t\tfromHas, toHas = sqlx.Has(from, &fromP), sqlx.Has(to, &toP)\n\t)\n\treturn fromHas != toHas || (fromHas && fromP.P != toP.P)\n}\n\n// IndexPartAttrChanged reports if the index-part attributes (collation or prefix) were changed.\nfunc (*diff) IndexPartAttrChanged(fromI, toI *schema.Index, i int) bool {\n\tvar s1, s2 SubPart\n\treturn sqlx.Has(fromI.Parts[i].Attrs, &s1) != sqlx.Has(toI.Parts[i].Attrs, &s2) || s1.Len != s2.Len\n}\n\n// ReferenceChanged reports if the foreign key referential action was changed.\nfunc (*diff) ReferenceChanged(from, to schema.ReferenceOption) bool {\n\t// According to MySQL docs, foreign key constraints are checked\n\t// immediately, so NO ACTION is the same as RESTRICT. Specifying\n\t// RESTRICT (or NO ACTION) is the same as omitting the ON DELETE\n\t// or ON UPDATE clause.\n\tif from == \"\" || from == schema.Restrict {\n\t\tfrom = schema.NoAction\n\t}\n\tif to == \"\" || to == schema.Restrict {\n\t\tto = schema.NoAction\n\t}\n\treturn from != to\n}\n\n// ForeignKeyAttrChanged reports if any of the foreign-key attributes were changed.\nfunc (*diff) ForeignKeyAttrChanged(_, _ []schema.Attr) bool {\n\treturn false\n}\n\n// Normalize implements the sqlx.Normalizer interface.\nfunc (d *diff) Normalize(from, to *schema.Table, opts *schema.DiffOptions) error {\n\tif opts.Mode.Is(schema.DiffModeNormalized) {\n\t\treturn nil // already normalized\n\t}\n\tindexes := make([]*schema.Index, 0, len(from.Indexes))\n\tfor _, idx := range from.Indexes {\n\t\t// MySQL requires that foreign key columns be indexed; Therefore, if the child\n\t\t// table is defined on non-indexed columns, an index is automatically created\n\t\t// to satisfy the constraint.\n\t\t// Therefore, if no such key was defined on the desired state, the diff will\n\t\t// recommend dropping it on migration. Therefore, we fix it by dropping it from\n\t\t// the current state manually.\n\t\tif _, ok := to.Index(idx.Name); ok || !keySupportsFK(from, idx) {\n\t\t\tindexes = append(indexes, idx)\n\t\t}\n\t}\n\tfrom.Indexes = indexes\n\n\t// In case the \"current\" state was inspected (or loaded) with the collation/charset attributes,\n\t// but there are not found on the desired state, detect what are the default settings for the\n\t// desired state of the table (based on database default) to avoid proposing unnecessary changes.\n\tif sqlx.Has(from.Attrs, &schema.Collation{}) {\n\t\tif err := d.defaultCollate(&to.Attrs); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif sqlx.Has(from.Attrs, &schema.Charset{}) {\n\t\tif err := d.defaultCharset(&to.Attrs); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// FindTable implements the DiffDriver.TableFinder method in order to provide\n// tables lookup that respect the \"lower_case_table_names\" system variable.\nfunc (d *diff) FindTable(s *schema.Schema, t1 *schema.Table) (*schema.Table, error) {\n\tswitch d.lcnames {\n\t// In mode 0: tables are stored as specified, and comparisons are case-sensitive.\n\tcase 0:\n\t\tt2, ok := s.Table(t1.Name)\n\t\tif !ok {\n\t\t\treturn nil, &schema.NotExistError{Err: fmt.Errorf(\"table %q was not found\", t1.Name)}\n\t\t}\n\t\treturn t2, nil\n\t// In mode 1: the table are stored in lowercase, but they are still\n\t// returned on inspection, because comparisons are not case-sensitive.\n\t// In mode 2: the tables are stored as given but compared in lowercase.\n\t// This option is not supported by Linux-based systems.\n\tcase 1, 2:\n\t\tvar matches []*schema.Table\n\t\tfor _, t2 := range s.Tables {\n\t\t\tif strings.ToLower(t2.Name) == strings.ToLower(t1.Name) {\n\t\t\t\tmatches = append(matches, t2)\n\t\t\t}\n\t\t}\n\t\tswitch n := len(matches); n {\n\t\tcase 0:\n\t\t\treturn nil, &schema.NotExistError{Err: fmt.Errorf(\"table %q was not found\", t1.Name)}\n\t\tcase 1:\n\t\t\treturn matches[0], nil\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"%d matches found for table %q\", n, t1.Name)\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unsupported 'lower_case_table_names' mode: %d\", d.lcnames)\n\t}\n}\n\n// collationChange returns the schema change for migrating the collation if\n// it was changed, and it is not the default attribute inherited from its parent.\nfunc (*diff) collationChange(from, top, to []schema.Attr) schema.Change {\n\tvar fromC, topC, toC schema.Collation\n\tswitch fromHas, topHas, toHas := sqlx.Has(from, &fromC), sqlx.Has(top, &topC), sqlx.Has(to, &toC); {\n\tcase !fromHas && !toHas:\n\tcase !fromHas:\n\t\treturn &schema.AddAttr{\n\t\t\tA: &toC,\n\t\t}\n\tcase !toHas:\n\t\t// There is no way to DROP a COLLATE that was configured on the table,\n\t\t// and it is not the default. Therefore, we use ModifyAttr and give it\n\t\t// the inherited (and default) collation from schema or server.\n\t\tif topHas && fromC.V != topC.V {\n\t\t\treturn &schema.ModifyAttr{\n\t\t\t\tFrom: &fromC,\n\t\t\t\tTo:   &topC,\n\t\t\t}\n\t\t}\n\tcase fromC.V != toC.V:\n\t\treturn &schema.ModifyAttr{\n\t\t\tFrom: &fromC,\n\t\t\tTo:   &toC,\n\t\t}\n\t}\n\treturn noChange\n}\n\n// engineChange returns the schema change for migrating the table engine in case\n// it was changed.\nfunc (*diff) engineChange(from, to []schema.Attr) schema.Change {\n\tvar fromE, toE Engine\n\tswitch fromHas, toHas := sqlx.Has(from, &fromE), sqlx.Has(to, &toE); {\n\t// Both engines are defined but different.\n\tcase fromHas && toHas && strings.ToLower(fromE.V) != strings.ToLower(toE.V):\n\t\treturn &schema.ModifyAttr{\n\t\t\tFrom: &fromE,\n\t\t\tTo:   &toE,\n\t\t}\n\t// If the engine attribute has been removed from the desired state (e.g., HCL), and the current state\n\t// is not the default, we change the engine to InnoDB (the default for MySQL, unless configured otherwise).\n\tcase fromHas && !toHas && !fromE.Default && strings.ToLower(fromE.V) != strings.ToLower(EngineInnoDB):\n\t\treturn &schema.ModifyAttr{\n\t\t\tFrom: &fromE,\n\t\t\tTo:   &Engine{V: EngineInnoDB, Default: true},\n\t\t}\n\t// In case the engine attribute was added to the desired state (e.g., HCL)\n\t// and it is not the default, we modify the engine to the desired value.\n\tcase !fromHas && toHas && !toE.Default && strings.ToLower(fromE.V) != strings.ToLower(EngineInnoDB):\n\t\treturn &schema.ModifyAttr{\n\t\t\tFrom: &Engine{V: EngineInnoDB, Default: true},\n\t\t\tTo:   &toE,\n\t\t}\n\t}\n\treturn noChange\n}\n\n// systemVerChange returns the schema change for migrating the system versioning\n// attributes if it was changed.\nfunc (d *diff) systemVerChange(from, to []schema.Attr) schema.Change {\n\tswitch fromHas, toHas := sqlx.Has(from, &SystemVersioned{}), sqlx.Has(to, &SystemVersioned{}); {\n\tcase fromHas && !toHas:\n\t\treturn &schema.DropAttr{A: &SystemVersioned{}}\n\tcase !fromHas && toHas:\n\t\treturn &schema.AddAttr{A: &SystemVersioned{}}\n\tdefault:\n\t\treturn noChange\n\t}\n}\n\n// charsetChange returns the schema change for migrating the collation if\n// it was changed, and it is not the default attribute inherited from its parent.\nfunc (*diff) charsetChange(from, top, to []schema.Attr) schema.Change {\n\tvar fromC, topC, toC schema.Charset\n\tswitch fromHas, topHas, toHas := sqlx.Has(from, &fromC), sqlx.Has(top, &topC), sqlx.Has(to, &toC); {\n\tcase !fromHas && !toHas:\n\tcase !fromHas:\n\t\treturn &schema.AddAttr{\n\t\t\tA: &toC,\n\t\t}\n\tcase !toHas:\n\t\t// There is no way to DROP a CHARSET that was configured on the table,\n\t\t// and it is not the default. Therefore, we use ModifyAttr and give it\n\t\t// the inherited (and default) collation from schema or server.\n\t\tif topHas && fromC.V != topC.V {\n\t\t\treturn &schema.ModifyAttr{\n\t\t\t\tFrom: &fromC,\n\t\t\t\tTo:   &topC,\n\t\t\t}\n\t\t}\n\tcase fromC.V != toC.V:\n\t\treturn &schema.ModifyAttr{\n\t\t\tFrom: &fromC,\n\t\t\tTo:   &toC,\n\t\t}\n\t}\n\treturn noChange\n}\n\n// columnCharsetChange indicates if there is a change to the column charset.\nfunc (d *diff) columnCharsetChanged(fromT *schema.Table, from, to *schema.Column) (bool, error) {\n\tif err := d.defaultCharset(&to.Attrs); err != nil {\n\t\treturn false, err\n\t}\n\tvar (\n\t\tfromC, topC, toC       schema.Charset\n\t\tfromHas, topHas, toHas = sqlx.Has(from.Attrs, &fromC), sqlx.Has(fromT.Attrs, &topC), sqlx.Has(to.Attrs, &toC)\n\t)\n\t// Column was updated with custom CHARSET that was dropped.\n\t// Hence, we should revert to the one defined on the table.\n\treturn fromHas && !toHas && topHas && fromC.V != topC.V ||\n\t\t// Custom CHARSET was added to the column. Hence,\n\t\t// Does not match the one defined in the table.\n\t\t!fromHas && toHas && topHas && toC.V != topC.V ||\n\t\t// CHARSET was explicitly changed.\n\t\tfromHas && toHas && fromC.V != toC.V, nil\n\n}\n\n// columnCollateChanged indicates if there is a change to the column charset.\nfunc (d *diff) columnCollateChanged(fromT *schema.Table, from, to *schema.Column) (bool, error) {\n\tif err := d.defaultCollate(&to.Attrs); err != nil {\n\t\treturn false, err\n\t}\n\tvar (\n\t\tfromC, topC, toC       schema.Collation\n\t\tfromHas, topHas, toHas = sqlx.Has(from.Attrs, &fromC), sqlx.Has(fromT.Attrs, &topC), sqlx.Has(to.Attrs, &toC)\n\t)\n\t// Column was updated with custom COLLATE that was dropped.\n\t// Hence, we should revert to the one defined on the table.\n\treturn fromHas && !toHas && topHas && fromC.V != topC.V ||\n\t\t// Custom COLLATE was added to the column. Hence,\n\t\t// Does not match the one defined in the table.\n\t\t!fromHas && toHas && topHas && toC.V != topC.V ||\n\t\t// COLLATE was explicitly changed.\n\t\tfromHas && toHas && fromC.V != toC.V, nil\n\n}\n\n// autoIncChange returns the schema change for changing the AUTO_INCREMENT\n// attribute in case it is not the default.\nfunc (*diff) autoIncChange(from, to []schema.Attr) schema.Change {\n\tvar fromA, toA AutoIncrement\n\tswitch fromHas, toHas := sqlx.Has(from, &fromA), sqlx.Has(to, &toA); {\n\t// Ignore if the AUTO_INCREMENT attribute was dropped from the desired schema.\n\tcase fromHas && !toHas:\n\t// The AUTO_INCREMENT exists in the desired schema, and may not exist in the inspected one.\n\t// This can happen because older versions of MySQL (< 8.0) stored the AUTO_INCREMENT counter\n\t// in main memory (not persistent), and the value is reset on process restart for empty tables.\n\tcase toA.V > 1 && toA.V > fromA.V:\n\t\t// Suggest a diff only if the desired value is greater than the inspected one,\n\t\t// because this attribute cannot be maintained in users schema and used to set\n\t\t// up only the initial value.\n\t\treturn &schema.ModifyAttr{\n\t\t\tFrom: &fromA,\n\t\t\tTo:   &toA,\n\t\t}\n\t}\n\treturn noChange\n}\n\n// indexType returns the index type from its attribute.\n// The default type is BTREE if no type was specified.\nfunc indexType(attr []schema.Attr) *IndexType {\n\tt := &IndexType{T: IndexTypeBTree}\n\tif sqlx.Has(attr, t) {\n\t\tt.T = strings.ToUpper(t.T)\n\t}\n\treturn t\n}\n\n// enforced returns the ENFORCED attribute for the CHECK\n// constraint. A CHECK is ENFORCED if not state otherwise.\nfunc enforced(attr []schema.Attr) bool {\n\tif e := (Enforced{}); sqlx.Has(attr, &e) {\n\t\treturn e.V\n\t}\n\treturn true\n}\n\n// noChange describes a zero change.\nvar noChange struct{ schema.Change }\n\nfunc (d *diff) typeChanged(from, to *schema.Column) (bool, error) {\n\tfromT, toT := from.Type.Type, to.Type.Type\n\tif fromT == nil || toT == nil {\n\t\treturn false, fmt.Errorf(\"mysql: missing type information for column %q\", from.Name)\n\t}\n\tif reflect.TypeOf(fromT) != reflect.TypeOf(toT) {\n\t\treturn true, nil\n\t}\n\tvar changed bool\n\tswitch fromT := fromT.(type) {\n\tcase *BitType, *schema.BinaryType, *schema.BoolType, *schema.DecimalType, *schema.FloatType,\n\t\t*schema.JSONType, *schema.StringType, *schema.SpatialType, *schema.TimeType, *schema.UUIDType, *NetworkType:\n\t\tft, err := FormatType(fromT)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\ttt, err := FormatType(toT)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tchanged = ft != tt\n\tcase *schema.EnumType:\n\t\ttoT := toT.(*schema.EnumType)\n\t\tchanged = !sqlx.ValuesEqual(fromT.Values, toT.Values)\n\tcase *schema.IntegerType:\n\t\ttoT := toT.(*schema.IntegerType)\n\t\t// MySQL v8.0.19 dropped both display-width\n\t\t// and zerofill from the information schema.\n\t\tif d.SupportsDisplayWidth() {\n\t\t\tft, _, _, err := parseColumn(fromT.T)\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\ttt, _, _, err := parseColumn(toT.T)\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tfromT.T, toT.T = ft[0], tt[0]\n\t\t}\n\t\tchanged = fromT.T != toT.T || fromT.Unsigned != toT.Unsigned\n\tcase *SetType:\n\t\ttoT := toT.(*SetType)\n\t\tchanged = !sqlx.ValuesEqual(fromT.Values, toT.Values)\n\tdefault:\n\t\treturn false, &sqlx.UnsupportedTypeError{Type: fromT}\n\t}\n\treturn changed, nil\n}\n\n// defaultChanged reports if the default value of a column was changed.\nfunc (d *diff) defaultChanged(from, to *schema.Column) (bool, error) {\n\td1, ok1 := sqlx.DefaultValue(from)\n\td2, ok2 := sqlx.DefaultValue(to)\n\tif ok1 != ok2 {\n\t\treturn true, nil\n\t}\n\tif d1 == d2 {\n\t\treturn false, nil\n\t}\n\tswitch from.Type.Type.(type) {\n\tcase *schema.BinaryType:\n\t\ta, err1 := binValue(d1)\n\t\tb, err2 := binValue(d2)\n\t\tif err1 != nil || err2 != nil {\n\t\t\treturn true, nil\n\t\t}\n\t\treturn !equalsStringValues(a, b), nil\n\tcase *schema.BoolType:\n\t\ta, err1 := boolValue(d1)\n\t\tb, err2 := boolValue(d2)\n\t\tif err1 == nil && err2 == nil {\n\t\t\treturn a != b, nil\n\t\t}\n\t\treturn false, nil\n\tcase *schema.IntegerType:\n\t\treturn !d.equalIntValues(d1, d2), nil\n\tcase *schema.FloatType, *schema.DecimalType:\n\t\treturn !d.equalFloatValues(d1, d2), nil\n\tcase *schema.EnumType, *SetType, *schema.StringType:\n\t\treturn !equalsStringValues(d1, d2), nil\n\tcase *schema.TimeType:\n\t\tx1 := strings.ToLower(strings.Trim(d1, \"' ()\"))\n\t\tx2 := strings.ToLower(strings.Trim(d2, \"' ()\"))\n\t\treturn !equalsStringValues(x1, x2), nil\n\tdefault:\n\t\tx1 := strings.Trim(d1, \"'\")\n\t\tx2 := strings.Trim(d2, \"'\")\n\t\treturn x1 != x2, nil\n\t}\n}\n\n// generatedChanged reports if the generated expression of a column was changed.\nfunc (*diff) generatedChanged(from, to *schema.Column) (bool, error) {\n\tvar (\n\t\tfromX, toX     schema.GeneratedExpr\n\t\tfromHas, toHas = sqlx.Has(from.Attrs, &fromX), sqlx.Has(to.Attrs, &toX)\n\t)\n\tif !fromHas && !toHas || fromHas && toHas && sqlx.MayWrap(fromX.Expr) == sqlx.MayWrap(toX.Expr) && storedOrVirtual(fromX.Type) == storedOrVirtual(toX.Type) {\n\t\treturn false, nil\n\t}\n\t// Checking validity of the change is done\n\t// by the planner (checkChangeGenerated).\n\treturn true, nil\n}\n\n// equalIntValues report if the 2 int default values are ~equal.\n// Note that default expression are not supported atm.\nfunc (d *diff) equalIntValues(x1, x2 string) bool {\n\tx1 = strings.ToLower(strings.Trim(x1, \"' \"))\n\tx2 = strings.ToLower(strings.Trim(x2, \"' \"))\n\tif x1 == x2 {\n\t\treturn true\n\t}\n\td1, err := strconv.ParseInt(x1, 10, 64)\n\tif err != nil {\n\t\t// Numbers are rounded down to their nearest integer.\n\t\tf, err := strconv.ParseFloat(x1, 64)\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t\td1 = int64(f)\n\t}\n\td2, err := strconv.ParseInt(x2, 10, 64)\n\tif err != nil {\n\t\t// Numbers are rounded down to their nearest integer.\n\t\tf, err := strconv.ParseFloat(x2, 64)\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t\td2 = int64(f)\n\t}\n\treturn d1 == d2\n}\n\n// equalFloatValues report if the 2 float default values are ~equal.\n// Note that default expression are not supported atm.\nfunc (d *diff) equalFloatValues(x1, x2 string) bool {\n\tx1 = strings.ToLower(strings.Trim(x1, \"' \"))\n\tx2 = strings.ToLower(strings.Trim(x2, \"' \"))\n\tif x1 == x2 {\n\t\treturn true\n\t}\n\td1, err := strconv.ParseFloat(x1, 64)\n\tif err != nil {\n\t\treturn false\n\t}\n\td2, err := strconv.ParseFloat(x2, 64)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn d1 == d2\n}\n\n// equalsStringValues report if the 2 string default values are\n// equal after dropping their quotes.\nfunc equalsStringValues(x1, x2 string) bool {\n\ta, err1 := sqlx.Unquote(x1)\n\tb, err2 := sqlx.Unquote(x2)\n\treturn a == b && err1 == nil && err2 == nil\n}\n\n// boolValue returns the MySQL boolean value from the given string (if it is known).\nfunc boolValue(x string) (bool, error) {\n\tswitch x {\n\tcase \"1\", \"'1'\", \"TRUE\", \"true\":\n\t\treturn true, nil\n\tcase \"0\", \"'0'\", \"FALSE\", \"false\":\n\t\treturn false, nil\n\tdefault:\n\t\treturn false, fmt.Errorf(\"mysql: unknown value: %q\", x)\n\t}\n}\n\n// binValue returns the MySQL binary value from the given string (if it is known).\nfunc binValue(x string) (string, error) {\n\tif !isHex(x) {\n\t\treturn x, nil\n\t}\n\td, err := hex.DecodeString(x[2:])\n\tif err != nil {\n\t\treturn x, err\n\t}\n\treturn string(d), nil\n}\n\n// keySupportsFK reports if the index key was created automatically by MySQL\n// to support the constraint. See sql/sql_table.cc#find_fk_supporting_key.\nfunc keySupportsFK(t *schema.Table, idx *schema.Index) bool {\n\tif _, ok := t.ForeignKey(idx.Name); ok {\n\t\treturn true\n\t}\nsearch:\n\tfor _, fk := range t.ForeignKeys {\n\t\tif len(fk.Columns) != len(idx.Parts) {\n\t\t\tcontinue\n\t\t}\n\t\tfor i, c := range fk.Columns {\n\t\t\tif idx.Parts[i].C == nil || idx.Parts[i].C.Name != c.Name {\n\t\t\t\tcontinue search\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n\treturn false\n}\n\n// defaultCollate appends the default COLLATE to the attributes in case a\n// custom character-set was defined for the element and the COLLATE was not.\nfunc (d *diff) defaultCollate(attrs *[]schema.Attr) error {\n\tvar charset schema.Charset\n\tif !sqlx.Has(*attrs, &charset) || sqlx.Has(*attrs, &schema.Collation{}) {\n\t\treturn nil\n\t}\n\td.ch2co.Do(func() {\n\t\td.ch2co.v, d.ch2co.err = d.CharsetToCollate(d.ExecQuerier)\n\t})\n\tif d.ch2co.err != nil {\n\t\treturn d.ch2co.err\n\t}\n\tif v, ok := d.ch2co.v[charset.V]; ok {\n\t\t// If charset is known, use its default collation.\n\t\tschema.ReplaceOrAppend(attrs, &schema.Collation{V: v})\n\t}\n\treturn nil\n}\n\n// defaultCharset appends the default CHARSET to the attributes in case a\n// custom collation was defined for the element and the CHARSET was not.\nfunc (d *diff) defaultCharset(attrs *[]schema.Attr) error {\n\tvar collate schema.Collation\n\tif !sqlx.Has(*attrs, &collate) || sqlx.Has(*attrs, &schema.Charset{}) {\n\t\treturn nil\n\t}\n\td.co2ch.Do(func() {\n\t\td.co2ch.v, d.co2ch.err = d.CollateToCharset(d.ExecQuerier)\n\t})\n\tif d.co2ch.err != nil {\n\t\treturn d.co2ch.err\n\t}\n\tif v, ok := d.co2ch.v[collate.V]; ok {\n\t\t// If collation is known, use its default charset.\n\t\tschema.ReplaceOrAppend(attrs, &schema.Charset{V: v})\n\t}\n\treturn nil\n}\n\nfunc (*diff) ViewAttrChanges(_, _ *schema.View) []schema.Change {\n\treturn nil // Not implemented.\n}\n"
  },
  {
    "path": "sql/mysql/diff_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysql\n\nimport (\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDiff_TableDiff(t *testing.T) {\n\ttype testcase struct {\n\t\tname        string\n\t\tfrom, to    *schema.Table\n\t\twantChanges []schema.Change\n\t\twantErr     bool\n\t}\n\ttests := []testcase{\n\t\t{\n\t\t\tname:    \"mismatched names\",\n\t\t\tfrom:    &schema.Table{Name: \"users\"},\n\t\t\tto:      &schema.Table{Name: \"pets\"},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"no changes\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\tto:   &schema.Table{Name: \"users\"},\n\t\t},\n\t\t{\n\t\t\tname: \"no changes\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Columns: []*schema.Column{{Name: \"enum\", Default: &schema.RawExpr{X: \"'A'\"}, Type: &schema.ColumnType{Type: &schema.EnumType{Values: []string{\"A\"}}}}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Columns: []*schema.Column{{Name: \"enum\", Default: &schema.RawExpr{X: `\"A\"`}, Type: &schema.ColumnType{Type: &schema.EnumType{Values: []string{\"A\"}}}}}},\n\t\t},\n\t\t{\n\t\t\tname: \"modify counter\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&AutoIncrement{V: 1}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Attrs: []schema.Attr{&AutoIncrement{V: 100}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &AutoIncrement{V: 1},\n\t\t\t\t\tTo:   &AutoIncrement{V: 100},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Attributes are specified and the same.\n\t\t{\n\t\t\tname: \"no engine changes\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: EngineInnoDB}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: EngineInnoDB}}},\n\t\t},\n\t\t// Attributes are specified and represent the same engine.\n\t\t{\n\t\t\tname: \"no engine changes\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: EngineInnoDB}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: \"INNODB\"}}},\n\t\t},\n\t\t// Attribute was dropped from the desired state, but the current state if the default (assumed one).\n\t\t{\n\t\t\tname: \"no engine changes\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: EngineInnoDB}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t},\n\t\t// Attribute was dropped from the desired state, but the current state if the default (explicitly specific as default).\n\t\t{\n\t\t\tname: \"no engine changes\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: EngineMyISAM, Default: true}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t},\n\t\t// The current state has no engine specified (unlikely case), and the desired state is set to the default (assumed one).\n\t\t{\n\t\t\tname: \"no engine changes\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\tto:   &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: EngineInnoDB, Default: true}}},\n\t\t},\n\t\t// Attributes are specified, but they do not represent the same engine.\n\t\t{\n\t\t\tname: \"engine changed\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: EngineInnoDB}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: EngineMyISAM}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &Engine{V: EngineInnoDB},\n\t\t\t\t\tTo:   &Engine{V: EngineMyISAM},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// The desired state has no engine specified, and the current state is not the default.\n\t\t{\n\t\t\tname: \"engine changed\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: EngineMyISAM}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &Engine{V: EngineMyISAM},\n\t\t\t\t\tTo:   &Engine{V: EngineInnoDB, Default: true}, // Assume InnoDB is the default.\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// The current state has no engine specified (unlikely case), and the desired state is not the default.\n\t\t{\n\t\t\tname: \"engine changed\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\tto:   &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&Engine{V: EngineMyISAM}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &Engine{V: EngineInnoDB, Default: true}, // Assume InnoDB is the default.\n\t\t\t\t\tTo:   &Engine{V: EngineMyISAM},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"add collation\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&schema.Charset{V: \"latin1\"}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Attrs: []schema.Attr{&schema.Collation{V: \"latin1_bin\"}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.AddAttr{\n\t\t\t\t\tA: &schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"drop collation means modify\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\", Attrs: []schema.Attr{&schema.Collation{V: \"utf8mb4_0900_ai_ci\"}}}, Attrs: []schema.Attr{&schema.Collation{V: \"utf8mb4_bin\"}}},\n\t\t\tto:   &schema.Table{Name: \"users\"},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Collation{V: \"utf8mb4_bin\"},\n\t\t\t\t\tTo:   &schema.Collation{V: \"utf8mb4_0900_ai_ci\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"modify collation\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&schema.Charset{V: \"latin1\"}, &schema.Collation{V: \"latin1_swedish_ci\"}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Attrs: []schema.Attr{&schema.Collation{V: \"latin1_bin\"}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\tTo:   &schema.Collation{V: \"latin1_bin\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"drop charset means modify\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\", Attrs: []schema.Attr{&schema.Charset{V: \"hebrew\"}}}, Attrs: []schema.Attr{&schema.Charset{V: \"hebrew_bin\"}}},\n\t\t\tto:   &schema.Table{Name: \"users\"},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Charset{V: \"hebrew_bin\"},\n\t\t\t\t\tTo:   &schema.Charset{V: \"hebrew\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"modify charset\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&schema.Charset{V: \"utf8\"}, &schema.Collation{V: \"utf8_general_ci\"}}},\n\t\t\tto:   &schema.Table{Name: \"users\", Attrs: []schema.Attr{&schema.Charset{V: \"utf8mb4\"}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Charset{V: \"utf8\"},\n\t\t\t\t\tTo:   &schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t},\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Collation{V: \"utf8_general_ci\"},\n\t\t\t\t\tTo:   &schema.Collation{V: \"utf8mb4_0900_ai_ci\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"add check\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\tto:   &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&schema.Check{Name: \"users_chk1_c1\", Expr: \"(`c1` <>_latin1\\\\'foo\\\\')\"}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.AddCheck{\n\t\t\t\t\tC: &schema.Check{Name: \"users_chk1_c1\", Expr: \"(`c1` <>_latin1\\\\'foo\\\\')\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"drop check\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&schema.Check{Name: \"users_chk1_c1\", Expr: \"(`c1` <>_latin1\\\\'foo\\\\')\"}}},\n\t\t\tto:   &schema.Table{Name: \"t1\"},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.DropCheck{\n\t\t\t\t\tC: &schema.Check{Name: \"users_chk1_c1\", Expr: \"(`c1` <>_latin1\\\\'foo\\\\')\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"modify check\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&schema.Check{Name: \"users_chk1_c1\", Expr: \"(`c1` <>_latin1\\\\'foo\\\\')\", Attrs: []schema.Attr{&Enforced{V: false}}}}},\n\t\t\tto:   &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&schema.Check{Name: \"users_chk1_c1\", Expr: \"(`c1` <>_latin1\\\\'foo\\\\')\", Attrs: []schema.Attr{&Enforced{V: true}}}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyCheck{\n\t\t\t\t\tFrom: &schema.Check{Name: \"users_chk1_c1\", Expr: \"(`c1` <>_latin1\\\\'foo\\\\')\", Attrs: []schema.Attr{&Enforced{V: false}}},\n\t\t\t\t\tTo:   &schema.Check{Name: \"users_chk1_c1\", Expr: \"(`c1` <>_latin1\\\\'foo\\\\')\", Attrs: []schema.Attr{&Enforced{V: true}}},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"add comment\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\tto:   &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&schema.Comment{Text: \"t1\"}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.AddAttr{\n\t\t\t\t\tA: &schema.Comment{Text: \"t1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"drop comment\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&schema.Comment{Text: \"t1\"}}},\n\t\t\tto:   &schema.Table{Name: \"t1\"},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Comment{Text: \"t1\"},\n\t\t\t\t\tTo:   &schema.Comment{Text: \"\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"modify comment\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&schema.Comment{Text: \"t1\"}}},\n\t\t\tto:   &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&schema.Comment{Text: \"t1!\"}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Comment{Text: \"t1\"},\n\t\t\t\t\tTo:   &schema.Comment{Text: \"t1!\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}},\n\t\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"tinyint\", Type: &schema.IntegerType{T: \"tinyint\"}}},\n\t\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"float\"}}, Default: &schema.Literal{V: \"0.00\"}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tto = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"c1\",\n\t\t\t\t\t\t\tType:    &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}, Null: true},\n\t\t\t\t\t\t\tDefault: &schema.RawExpr{X: \"{}\"},\n\t\t\t\t\t\t\tAttrs:   []schema.Attr{&schema.Comment{Text: \"json comment\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"float\"}}, Default: &schema.Literal{V: \"0.00\"}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"columns\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\tFrom:   from.Columns[0],\n\t\t\t\t\t\tTo:     to.Columns[0],\n\t\t\t\t\t\tChange: schema.ChangeNull | schema.ChangeComment | schema.ChangeDefault,\n\t\t\t\t\t},\n\t\t\t\t\t&schema.DropColumn{C: from.Columns[1]},\n\t\t\t\t\t&schema.AddColumn{C: to.Columns[1]},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\t// Custom CHARSET was dropped.\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tSetCharset(\"utf8\").\n\t\t\t\t\tSetCollation(\"utf8_general_ci\").\n\t\t\t\t\tAddColumns(schema.NewStringColumn(\"c1\", \"text\").SetCharset(\"latin1\"))\n\t\t\t\tto = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tSetCharset(\"utf8\").\n\t\t\t\t\tAddColumns(schema.NewStringColumn(\"c1\", \"text\"))\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"columns\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\tFrom:   from.Columns[0],\n\t\t\t\t\t\tTo:     to.Columns[0],\n\t\t\t\t\t\tChange: schema.ChangeCharset,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\t// Custom CHARSET was added.\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tSetCharset(\"utf8\").\n\t\t\t\t\tSetCollation(\"utf8_general_ci\").\n\t\t\t\t\tAddColumns(schema.NewStringColumn(\"c1\", \"text\"))\n\t\t\t\tto = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tSetCharset(\"utf8\").\n\t\t\t\t\tAddColumns(schema.NewStringColumn(\"c1\", \"text\").SetCharset(\"latin1\"))\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"columns\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\tFrom:   from.Columns[0],\n\t\t\t\t\t\tTo:     to.Columns[0],\n\t\t\t\t\t\tChange: schema.ChangeCharset | schema.ChangeCollate,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\t// Custom CHARSET was changed.\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tSetCharset(\"utf8\").\n\t\t\t\t\tSetCollation(\"utf8_general_ci\").\n\t\t\t\t\tAddColumns(schema.NewStringColumn(\"c1\", \"text\").SetCharset(\"hebrew\"))\n\t\t\t\tto = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tSetCharset(\"utf8\").\n\t\t\t\t\tSetCollation(\"utf8_general_ci\").\n\t\t\t\t\tAddColumns(schema.NewStringColumn(\"c1\", \"text\").SetCharset(\"latin1\"))\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"columns\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\tFrom:   from.Columns[0],\n\t\t\t\t\t\tTo:     to.Columns[0],\n\t\t\t\t\t\tChange: schema.ChangeCharset | schema.ChangeCollate,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\t// Nop CHARSET change.\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tSetCharset(\"utf8\").\n\t\t\t\t\tSetCollation(\"utf8_general_ci\").\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewStringColumn(\"c1\", \"text\").SetCharset(\"utf8\"),\n\t\t\t\t\t\tschema.NewStringColumn(\"c2\", \"text\"),\n\t\t\t\t\t)\n\t\t\t\tto = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tSetCollation(\"utf8_general_ci\").\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewStringColumn(\"c1\", \"text\"),\n\t\t\t\t\t\tschema.NewStringColumn(\"c2\", \"text\").SetCharset(\"utf8\"),\n\t\t\t\t\t)\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"columns\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\ts    = schema.New(\"public\")\n\t\t\t\tfrom = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(s).\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\"),\n\t\t\t\t\t\tschema.NewIntColumn(\"c2\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\tschema.NewIntColumn(\"c3\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\"}),\n\t\t\t\t\t\tschema.NewIntColumn(\"c4\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"VIRTUAL\"}),\n\t\t\t\t\t\tschema.NewIntColumn(\"c5\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"PERSISTENT\"}),\n\t\t\t\t\t\tschema.NewIntColumn(\"c6\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"PERSISTENT\"}),\n\t\t\t\t\t)\n\t\t\t\tto = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(s).\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t// Add generated expression.\n\t\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\t// Drop generated expression.\n\t\t\t\t\t\tschema.NewIntColumn(\"c2\", \"int\"),\n\t\t\t\t\t\t// Modify generated expression.\n\t\t\t\t\t\tschema.NewIntColumn(\"c3\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"2\"}),\n\t\t\t\t\t\t// No change.\n\t\t\t\t\t\tschema.NewIntColumn(\"c4\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\"}),\n\t\t\t\t\t\tschema.NewIntColumn(\"c5\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\tschema.NewIntColumn(\"c6\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"(1)\", Type: \"PERSISTENT\"}),\n\t\t\t\t\t)\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"modify column generated\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{From: from.Columns[0], To: to.Columns[0], Change: schema.ChangeGenerated},\n\t\t\t\t\t&schema.ModifyColumn{From: from.Columns[1], To: to.Columns[1], Change: schema.ChangeGenerated},\n\t\t\t\t\t&schema.ModifyColumn{From: from.Columns[2], To: to.Columns[2], Change: schema.ChangeGenerated},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}},\n\t\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"tinyint\", Type: &schema.IntegerType{T: \"tinyint\"}}},\n\t\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Raw: \"text\", Type: &schema.StringType{T: \"text\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tto = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}},\n\t\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"tinyint\", Type: &schema.IntegerType{T: \"tinyint\"}}},\n\t\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Raw: \"text\", Type: &schema.StringType{T: \"text\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t)\n\t\t\tfrom.Indexes = []*schema.Index{\n\t\t\t\t{Name: \"c1_index\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[0]}}},\n\t\t\t\t{Name: \"c2_unique\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}},\n\t\t\t\t{Name: \"c1_prefix\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1], Attrs: []schema.Attr{&SubPart{Len: 50}}}}},\n\t\t\t\t{Name: \"c1_desc\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}},\n\t\t\t\t{Name: \"parser\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[3]}}, Attrs: []schema.Attr{&IndexType{T: IndexTypeFullText}, &IndexParser{P: \"ngram\"}}},\n\t\t\t}\n\t\t\tto.Indexes = []*schema.Index{\n\t\t\t\t{Name: \"c1_index\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[0]}}},\n\t\t\t\t{Name: \"c3_unique\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: to.Columns[1]}}},\n\t\t\t\t{Name: \"c1_prefix\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[0], Attrs: []schema.Attr{&SubPart{Len: 100}}}}},\n\t\t\t\t{Name: \"c1_desc\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1], Desc: true}}},\n\t\t\t\t{Name: \"parser\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[3]}}, Attrs: []schema.Attr{&IndexType{T: IndexTypeFullText}}},\n\t\t\t}\n\t\t\treturn testcase{\n\t\t\t\tname: \"indexes\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[0], To: to.Indexes[0], Change: schema.ChangeUnique},\n\t\t\t\t\t&schema.DropIndex{I: from.Indexes[1]},\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[2], To: to.Indexes[2], Change: schema.ChangeParts},\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[3], To: to.Indexes[3], Change: schema.ChangeParts},\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[4], To: to.Indexes[4], Change: schema.ChangeAttr},\n\t\t\t\t\t&schema.AddIndex{I: to.Indexes[1]},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tfrom := schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\"))\n\t\t\tto := schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\"))\n\t\t\tto.SetPrimaryKey(schema.NewPrimaryKey(to.Columns...))\n\t\t\treturn testcase{\n\t\t\t\tname: \"add primary-key\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.AddPrimaryKey{P: to.PrimaryKey},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tfrom := schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\"))\n\t\t\tfrom.SetPrimaryKey(schema.NewPrimaryKey(from.Columns...))\n\t\t\tto := schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\"))\n\t\t\treturn testcase{\n\t\t\t\tname: \"drop primary-key\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.DropPrimaryKey{P: from.PrimaryKey},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tfrom := schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\tAddColumns(schema.NewStringColumn(\"id\", \"varchar(255)\"))\n\t\t\tfrom.SetPrimaryKey(schema.NewPrimaryKey(from.Columns...))\n\t\t\tto := schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\tAddColumns(schema.NewStringColumn(\"id\", \"varchar(255)\"))\n\t\t\tto.SetPrimaryKey(\n\t\t\t\tschema.NewPrimaryKey(from.Columns...).\n\t\t\t\t\tAddAttrs(&IndexType{T: IndexTypeHash}),\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"modify primary-key\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyPrimaryKey{\n\t\t\t\t\t\tFrom:   from.PrimaryKey,\n\t\t\t\t\t\tTo:     to.PrimaryKey,\n\t\t\t\t\t\tChange: schema.ChangeAttr,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tref = &schema.Table{\n\t\t\t\t\tName: \"t2\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t\t{Name: \"ref_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tfrom = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"t2_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tto = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"t2_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t)\n\t\t\tfrom.ForeignKeys = []*schema.ForeignKey{\n\t\t\t\t{Table: from, Columns: from.Columns, RefTable: ref, RefColumns: ref.Columns[:1]},\n\t\t\t}\n\t\t\tto.ForeignKeys = []*schema.ForeignKey{\n\t\t\t\t{Table: to, Columns: to.Columns, RefTable: ref, RefColumns: ref.Columns[1:]},\n\t\t\t}\n\t\t\treturn testcase{\n\t\t\t\tname: \"foreign-keys\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyForeignKey{\n\t\t\t\t\t\tFrom:   from.ForeignKeys[0],\n\t\t\t\t\t\tTo:     to.ForeignKeys[0],\n\t\t\t\t\t\tChange: schema.ChangeRefColumn,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t}\n\tfor _, tt := range tests {\n\t\tdb, m, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\t\tmock{m}.version(\"8.0.19\")\n\t\tdrv, err := Open(db)\n\t\trequire.NoError(t, err)\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tchanges, err := drv.TableDiff(tt.from, tt.to)\n\t\t\trequire.Equalf(t, tt.wantErr, err != nil, \"error: %q\", err)\n\t\t\trequire.EqualValues(t, tt.wantChanges, changes)\n\t\t})\n\t}\n}\n\nfunc TestDiff_UnsupportedChecks(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmock{m}.version(\"5.6.35\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\ts := schema.New(\"public\")\n\tchanges, err := drv.TableDiff(\n\t\tschema.NewTable(\"t\").SetSchema(s),\n\t\tschema.NewTable(\"t\").SetSchema(s).AddChecks(schema.NewCheck()),\n\t)\n\trequire.Nil(t, changes)\n\trequire.EqualError(t, err, `version \"5.6.35\" does not support CHECK constraints`)\n}\n\nfunc TestDiff_SchemaDiff(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmock{m}.version(\"8.0.19\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\n\tchanges, err := drv.SchemaDiff(&schema.Schema{Name: \"public\"}, &schema.Schema{Name: \"test\"})\n\trequire.Error(t, err)\n\trequire.Nil(t, changes)\n\n\tfrom := &schema.Schema{\n\t\tRealm: &schema.Realm{\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Collation{V: \"latin1\"},\n\t\t\t},\n\t\t},\n\t\tTables: []*schema.Table{\n\t\t\t{Name: \"users\"},\n\t\t\t{Name: \"pets\"},\n\t\t},\n\t\tAttrs: []schema.Attr{\n\t\t\t&schema.Collation{V: \"latin1\"},\n\t\t},\n\t}\n\tto := &schema.Schema{\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"t2_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{Name: \"groups\"},\n\t\t},\n\t\tAttrs: []schema.Attr{\n\t\t\t&schema.Collation{V: \"utf8\"},\n\t\t},\n\t}\n\tfrom.Tables[0].Schema = from\n\tfrom.Tables[1].Schema = from\n\tchanges, err = drv.SchemaDiff(from, to)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, []schema.Change{\n\t\t&schema.ModifySchema{S: to, Changes: []schema.Change{&schema.ModifyAttr{From: from.Attrs[0], To: to.Attrs[0]}}},\n\t\t&schema.ModifyTable{T: to.Tables[0], Changes: []schema.Change{&schema.AddColumn{C: to.Tables[0].Columns[0]}}},\n\t\t&schema.DropTable{T: from.Tables[1]},\n\t\t&schema.AddTable{T: to.Tables[1]},\n\t}, changes)\n}\n\nfunc TestDiff_LowerCaseMode(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmock{m}.lcmode(\"8.0.19\", \"1\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\tchanges, err := drv.SchemaDiff(\n\t\tschema.New(\"public\").AddTables(schema.NewTable(\"t\"), schema.NewTable(\"S\")),\n\t\tschema.New(\"public\").AddTables(schema.NewTable(\"T\"), schema.NewTable(\"s\")),\n\t)\n\trequire.NoError(t, err)\n\trequire.Nil(t, changes)\n\n\tchanges, err = drv.SchemaDiff(\n\t\tschema.New(\"public\").AddTables(schema.NewTable(\"t\")),\n\t\tschema.New(\"public\").AddTables(schema.NewTable(\"T\"), schema.NewTable(\"t\")),\n\t)\n\trequire.EqualError(t, err, `2 matches found for table \"t\"`)\n\trequire.Nil(t, changes)\n\n\tchanges, err = drv.SchemaDiff(\n\t\tschema.New(\"public\").AddTables(schema.NewTable(\"t\")),\n\t\tschema.New(\"public\").AddTables(schema.NewTable(\"s\"), schema.NewTable(\"S\")),\n\t)\n\trequire.NoError(t, err)\n\trequire.Len(t, changes, 3)\n\n\tmock{m}.lcmode(\"8.0.19\", \"2\")\n\tdrv, err = Open(db)\n\trequire.NoError(t, err)\n\tchanges, err = drv.SchemaDiff(\n\t\tschema.New(\"public\").AddTables(schema.NewTable(\"t\"), schema.NewTable(\"S\")),\n\t\tschema.New(\"public\").AddTables(schema.NewTable(\"T\"), schema.NewTable(\"s\")),\n\t)\n\trequire.NoError(t, err)\n\trequire.Nil(t, changes)\n\n\tmock{m}.lcmode(\"8.0.19\", \"3\")\n\tdrv, err = Open(db)\n\trequire.NoError(t, err)\n\tchanges, err = drv.SchemaDiff(\n\t\tschema.New(\"public\").AddTables(schema.NewTable(\"t\"), schema.NewTable(\"S\")),\n\t\tschema.New(\"public\").AddTables(schema.NewTable(\"T\"), schema.NewTable(\"s\")),\n\t)\n\trequire.EqualError(t, err, `unsupported 'lower_case_table_names' mode: 3`)\n\trequire.Nil(t, changes)\n}\n\nfunc TestDiff_RealmDiff(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmock{m}.version(\"8.0.19\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\tfrom := &schema.Realm{\n\t\tSchemas: []*schema.Schema{\n\t\t\t{\n\t\t\t\tName: \"public\",\n\t\t\t\tTables: []*schema.Table{\n\t\t\t\t\t{Name: \"users\"},\n\t\t\t\t\t{Name: \"pets\"},\n\t\t\t\t},\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Collation{V: \"latin1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"internal\",\n\t\t\t\tTables: []*schema.Table{\n\t\t\t\t\t{Name: \"pets\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tto := &schema.Realm{\n\t\tSchemas: []*schema.Schema{\n\t\t\t{\n\t\t\t\tName: \"public\",\n\t\t\t\tTables: []*schema.Table{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"t2_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{Name: \"pets\"},\n\t\t\t\t},\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Collation{V: \"utf8\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"test\",\n\t\t\t\tTables: []*schema.Table{\n\t\t\t\t\t{Name: \"pets\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfrom.Schemas[0].Realm = from\n\tfrom.Schemas[0].Tables[0].Schema = from.Schemas[0]\n\tfrom.Schemas[0].Tables[1].Schema = from.Schemas[0]\n\tto.Schemas[0].Realm = to\n\tto.Schemas[0].Tables[0].Schema = to.Schemas[0]\n\tchanges, err := drv.RealmDiff(from, to)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, []schema.Change{\n\t\t&schema.ModifySchema{S: to.Schemas[0], Changes: []schema.Change{&schema.ModifyAttr{From: from.Schemas[0].Attrs[0], To: to.Schemas[0].Attrs[0]}}},\n\t\t&schema.ModifyTable{T: to.Schemas[0].Tables[0], Changes: []schema.Change{&schema.AddColumn{C: to.Schemas[0].Tables[0].Columns[0]}}},\n\t\t&schema.DropSchema{S: from.Schemas[1]},\n\t\t&schema.AddSchema{S: to.Schemas[1]},\n\t\t&schema.AddTable{T: to.Schemas[1].Tables[0]},\n\t}, changes)\n}\n\nfunc TestDefaultDiff(t *testing.T) {\n\tchanges, err := DefaultDiff.SchemaDiff(\n\t\tschema.New(\"public\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"users\").AddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t),\n\t\tschema.New(\"public\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.Len(t, changes, 1)\n\trequire.IsType(t, &schema.DropTable{}, changes[0])\n\n\tchanges, err = DefaultDiff.SchemaDiff(\n\t\tschema.New(\"public\").\n\t\t\tSetCollation(\"utf8mb4_0900_ai_ci\").\n\t\t\tSetCharset(\"utf8mb4\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"users\").SetCollation(\"utf8mb4_bin\"),\n\t\t\t),\n\t\tschema.New(\"public\").\n\t\t\tSetCollation(\"utf8mb4_0900_ai_ci\").\n\t\t\tSetCharset(\"utf8mb4\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"users\").SetCollation(\"utf8mb4_bin\"),\n\t\t\t),\n\t)\n\trequire.NoError(t, err)\n\trequire.Empty(t, changes)\n\n\tchanges, err = DefaultDiff.SchemaDiff(\n\t\tschema.New(\"public\").\n\t\t\tSetCollation(\"utf8mb4_0900_ai_ci\").\n\t\t\tSetCharset(\"utf8mb4\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"users\").SetCharset(\"utf8mb4\"),\n\t\t\t),\n\t\tschema.New(\"public\").\n\t\t\tSetCollation(\"utf8mb4_0900_ai_ci\").\n\t\t\tSetCharset(\"utf8mb4\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"users\").SetCharset(\"utf8mb4\"),\n\t\t\t),\n\t)\n\trequire.NoError(t, err)\n\trequire.Empty(t, changes)\n}\n\nfunc TestSkipChanges(t *testing.T) {\n\tt.Run(\"DropSchema\", func(t *testing.T) {\n\t\tfrom, to := schema.NewRealm(schema.New(\"public\")), schema.NewRealm()\n\t\tchanges, err := DefaultDiff.RealmDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, changes, 1)\n\t\tchanges, err = DefaultDiff.RealmDiff(from, to, schema.DiffSkipChanges(&schema.DropSchema{}))\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\t})\n\n\tt.Run(\"DropTable\", func(t *testing.T) {\n\t\tfrom, to := schema.NewRealm(schema.New(\"public\").AddTables(schema.NewTable(\"users\"))), schema.NewRealm(schema.New(\"public\"))\n\t\tchanges, err := DefaultDiff.RealmDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, changes, 1)\n\t\tchanges, err = DefaultDiff.SchemaDiff(from.Schemas[0], to.Schemas[0])\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, changes, 1)\n\n\t\tchanges, err = DefaultDiff.RealmDiff(from, to, schema.DiffSkipChanges(&schema.DropTable{}))\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\t\tchanges, err = DefaultDiff.SchemaDiff(from.Schemas[0], to.Schemas[0], schema.DiffSkipChanges(&schema.DropTable{}))\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\t})\n\n\tt.Run(\"ModifyTable\", func(t *testing.T) {\n\t\tfrom := schema.NewRealm(\n\t\t\tschema.New(\"public\").AddTables(\n\t\t\t\tschema.NewTable(\"users\").\n\t\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\")).\n\t\t\t\t\tAddIndexes(schema.NewIndex(\"users_id_idx\").AddColumns(schema.NewIntColumn(\"id\", \"int\"))),\n\t\t\t),\n\t\t)\n\t\tto := schema.NewRealm(schema.New(\"public\").AddTables(schema.NewTable(\"users\")))\n\t\tchanges, err := DefaultDiff.RealmDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, changes, 1)\n\t\trequire.Len(t, changes[0].(*schema.ModifyTable).Changes, 2)\n\t\tchanges, err = DefaultDiff.SchemaDiff(from.Schemas[0], to.Schemas[0])\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, changes, 1)\n\t\trequire.Len(t, changes[0].(*schema.ModifyTable).Changes, 2)\n\n\t\tchanges, err = DefaultDiff.RealmDiff(from, to, schema.DiffSkipChanges(&schema.ModifyTable{}))\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\t\tchanges, err = DefaultDiff.SchemaDiff(from.Schemas[0], to.Schemas[0], schema.DiffSkipChanges(&schema.ModifyTable{}))\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\n\t\tchanges, err = DefaultDiff.RealmDiff(from, to, schema.DiffSkipChanges(&schema.DropColumn{}, &schema.DropIndex{}))\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\t\tchanges, err = DefaultDiff.SchemaDiff(from.Schemas[0], to.Schemas[0], schema.DiffSkipChanges(&schema.DropColumn{}, &schema.DropIndex{}))\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\n\t\t// Ignore partial table changes.\n\t\tchanges, err = DefaultDiff.RealmDiff(from, to, schema.DiffSkipChanges(&schema.DropColumn{}))\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, changes, 1)\n\t\trequire.Len(t, changes[0].(*schema.ModifyTable).Changes, 1)\n\t\trequire.IsType(t, &schema.DropIndex{}, changes[0].(*schema.ModifyTable).Changes[0])\n\t\tchanges, err = DefaultDiff.SchemaDiff(from.Schemas[0], to.Schemas[0], schema.DiffSkipChanges(&schema.DropIndex{}))\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, changes, 1)\n\t\trequire.Len(t, changes[0].(*schema.ModifyTable).Changes, 1)\n\t\trequire.IsType(t, &schema.DropColumn{}, changes[0].(*schema.ModifyTable).Changes[0])\n\t})\n}\n"
  },
  {
    "path": "sql/mysql/driver_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysql\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/mysql/internal/mysqlversion\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t\"ariga.io/atlas/sql/sqlspec\"\n)\n\ntype (\n\t// Driver represents a MySQL driver for introspecting database schemas,\n\t// generating diff between schema elements and apply migrations changes.\n\tDriver struct {\n\t\t*conn\n\t\tschema.Differ\n\t\tschema.Inspector\n\t\tmigrate.PlanApplier\n\t}\n\n\t// database connection and its information.\n\tconn struct {\n\t\tschema.ExecQuerier\n\t\t// The schema was set in the path (schema connection).\n\t\tschema string\n\t\t// System variables that are set on `Open`.\n\t\tmysqlversion.V\n\t\tcollate string\n\t\tcharset string\n\t\tlcnames int\n\t}\n)\n\nvar _ interface {\n\tmigrate.StmtScanner\n\tschema.TypeParseFormatter\n} = (*Driver)(nil)\n\n// DriverName and DriverMaria holds the names used for registration.\nconst (\n\tDriverName  = \"mysql\"\n\tDriverMaria = \"mariadb\"\n)\n\nfunc init() {\n\tsqlclient.Register(\n\t\tDriverName,\n\t\topener(DriverName),\n\t\tsqlclient.RegisterDriverOpener(Open),\n\t\tsqlclient.RegisterCodec(codec, codec),\n\t\tsqlclient.RegisterFlavours(\"mysql+unix\"),\n\t\tsqlclient.RegisterURLParser(parser{}),\n\t)\n\tsqlclient.Register(\n\t\tDriverMaria,\n\t\topener(DriverMaria),\n\t\tsqlclient.RegisterDriverOpener(Open),\n\t\tsqlclient.RegisterCodec(mariaCodec, mariaCodec),\n\t\tsqlclient.RegisterFlavours(\"mariadb+unix\", \"maria\", \"maria+unix\"),\n\t\tsqlclient.RegisterURLParser(parser{}),\n\t)\n}\n\n// Open opens a new MySQL driver.\nfunc Open(db schema.ExecQuerier) (migrate.Driver, error) {\n\tc := &conn{ExecQuerier: db}\n\trows, err := db.QueryContext(context.Background(), variablesQuery)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"mysql: query system variables: %w\", err)\n\t}\n\tif err := sqlx.ScanOne(rows, &c.V, &c.collate, &c.charset, &c.lcnames); err != nil {\n\t\treturn nil, fmt.Errorf(\"mysql: scan system variables: %w\", err)\n\t}\n\tif c.TiDB() {\n\t\treturn &Driver{\n\t\t\tconn:        c,\n\t\t\tDiffer:      &sqlx.Diff{DiffDriver: &tdiff{diff{conn: c}}},\n\t\t\tInspector:   &tinspect{inspect{c}},\n\t\t\tPlanApplier: &tplanApply{planApply{c}},\n\t\t}, nil\n\t}\n\treturn &Driver{\n\t\tconn:        c,\n\t\tDiffer:      &sqlx.Diff{DiffDriver: &diff{conn: c}},\n\t\tInspector:   &inspect{c},\n\t\tPlanApplier: &planApply{c},\n\t}, nil\n}\n\n// opener for the given driver name.\nfunc opener(name string) sqlclient.OpenerFunc {\n\treturn func(_ context.Context, u *url.URL) (*sqlclient.Client, error) {\n\t\tur := parser{}.ParseURL(u)\n\t\tdb, err := sql.Open(DriverName, ur.DSN)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdrv, err := Open(db)\n\t\tif err != nil {\n\t\t\tif cerr := db.Close(); cerr != nil {\n\t\t\t\terr = fmt.Errorf(\"%w: %v\", err, cerr)\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\tdrv.(*Driver).schema = ur.Schema\n\t\treturn &sqlclient.Client{\n\t\t\tName:   name,\n\t\t\tDB:     db,\n\t\t\tURL:    ur,\n\t\t\tDriver: drv,\n\t\t}, nil\n\t}\n}\n\n// NormalizeRealm returns the normal representation of the given database.\nfunc (d *Driver) NormalizeRealm(ctx context.Context, r *schema.Realm) (*schema.Realm, error) {\n\treturn (&sqlx.DevDriver{Driver: d}).NormalizeRealm(ctx, r)\n}\n\n// NormalizeSchema returns the normal representation of the given database.\nfunc (d *Driver) NormalizeSchema(ctx context.Context, s *schema.Schema) (*schema.Schema, error) {\n\treturn (&sqlx.DevDriver{Driver: d}).NormalizeSchema(ctx, s)\n}\n\n// Lock implements the schema.Locker interface.\nfunc (d *Driver) Lock(ctx context.Context, name string, timeout time.Duration) (schema.UnlockFunc, error) {\n\tconn, err := sqlx.SingleConn(ctx, d.ExecQuerier)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := acquire(ctx, conn, name, timeout); err != nil {\n\t\tconn.Close()\n\t\treturn nil, err\n\t}\n\treturn func() error {\n\t\tdefer conn.Close()\n\t\trows, err := conn.QueryContext(ctx, \"SELECT RELEASE_LOCK(?)\", name)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch released, err := sqlx.ScanNullBool(rows); {\n\t\tcase err != nil:\n\t\t\treturn err\n\t\tcase !released.Valid || !released.Bool:\n\t\t\treturn fmt.Errorf(\"sql/mysql: failed releasing a named lock %q\", name)\n\t\t}\n\t\treturn nil\n\t}, nil\n}\n\n// Snapshot implements migrate.Snapshoter.\nfunc (d *Driver) Snapshot(ctx context.Context) (migrate.RestoreFunc, error) {\n\t// If the connection is bound to a schema, we can restore the state if the schema has no tables.\n\ts, err := d.InspectSchema(ctx, \"\", nil)\n\tif err != nil && !schema.IsNotExistError(err) {\n\t\treturn nil, err\n\t}\n\t// If a schema was found, it has to have no tables attached to be considered clean.\n\tif s != nil {\n\t\tif len(s.Tables) > 0 {\n\t\t\treturn nil, &migrate.NotCleanError{\n\t\t\t\tState:  schema.NewRealm(s),\n\t\t\t\tReason: fmt.Sprintf(\"found table %q in schema %q\", s.Tables[0].Name, s.Name),\n\t\t\t}\n\t\t}\n\t\treturn d.SchemaRestoreFunc(s), nil\n\t}\n\t// Otherwise, the database can not have any schema.\n\trealm, err := d.InspectRealm(ctx, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(realm.Schemas) > 0 {\n\t\treturn nil, &migrate.NotCleanError{State: realm, Reason: fmt.Sprintf(\"found schema %q\", realm.Schemas[0].Name)}\n\t}\n\treturn d.RealmRestoreFunc(realm), nil\n}\n\n// SchemaRestoreFunc returns a function that restores the given schema to its desired state.\nfunc (d *Driver) SchemaRestoreFunc(desired *schema.Schema) migrate.RestoreFunc {\n\treturn func(ctx context.Context) error {\n\t\tcurrent, err := d.InspectSchema(ctx, desired.Name, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tchanges, err := d.SchemaDiff(current, desired)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn d.ApplyChanges(ctx, changes)\n\t}\n}\n\n// RealmRestoreFunc returns a function that restores the given realm to its desired state.\nfunc (d *Driver) RealmRestoreFunc(desired *schema.Realm) migrate.RestoreFunc {\n\treturn func(ctx context.Context) error {\n\t\tcurrent, err := d.InspectRealm(ctx, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tchanges, err := d.RealmDiff(current, desired)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn d.ApplyChanges(ctx, changes)\n\t}\n}\n\n// CheckClean implements migrate.CleanChecker.\nfunc (d *Driver) CheckClean(ctx context.Context, revT *migrate.TableIdent) error {\n\tif revT == nil { // accept nil values\n\t\trevT = &migrate.TableIdent{}\n\t}\n\ts, err := d.InspectSchema(ctx, \"\", nil)\n\tif err != nil && !schema.IsNotExistError(err) {\n\t\treturn err\n\t}\n\tif s != nil {\n\t\tif len(s.Tables) == 0 || (revT.Schema == \"\" || s.Name == revT.Schema) && len(s.Tables) == 1 && s.Tables[0].Name == revT.Name {\n\t\t\treturn nil\n\t\t}\n\t\treturn &migrate.NotCleanError{\n\t\t\tState:  schema.NewRealm(s),\n\t\t\tReason: fmt.Sprintf(\"found table %q in schema %q\", s.Tables[0].Name, s.Name),\n\t\t}\n\t}\n\tr, err := d.InspectRealm(ctx, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tswitch n := len(r.Schemas); {\n\tcase n > 1:\n\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found multiple schemas: %d\", len(r.Schemas))}\n\tcase n == 1 && r.Schemas[0].Name != revT.Schema:\n\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found schema %q\", r.Schemas[0].Name)}\n\tcase n == 1 && len(r.Schemas[0].Tables) > 1:\n\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found multiple tables: %d\", len(r.Schemas[0].Tables))}\n\tcase n == 1 && len(r.Schemas[0].Tables) == 1 && r.Schemas[0].Tables[0].Name != revT.Name:\n\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found table %q\", r.Schemas[0].Tables[0].Name)}\n\t}\n\treturn nil\n}\n\n// Version returns the version of the connected database.\nfunc (d *Driver) Version() string {\n\treturn string(d.conn.V)\n}\n\n// FormatType converts schema type to its column form in the database.\nfunc (*Driver) FormatType(t schema.Type) (string, error) {\n\treturn FormatType(t)\n}\n\n// ParseType returns the schema.Type value represented by the given string.\nfunc (*Driver) ParseType(s string) (schema.Type, error) {\n\treturn ParseType(s)\n}\n\n// StmtBuilder is a helper method used to build statements with MySQL formatting.\nfunc (*Driver) StmtBuilder(opts migrate.PlanOptions) *sqlx.Builder {\n\treturn &sqlx.Builder{\n\t\tQuoteOpening: '`',\n\t\tQuoteClosing: '`',\n\t\tSchema:       opts.SchemaQualifier,\n\t\tIndent:       opts.Indent,\n\t}\n}\n\n// ScanStmts implements migrate.StmtScanner.\nfunc (*Driver) ScanStmts(input string) ([]*migrate.Stmt, error) {\n\treturn (&migrate.Scanner{\n\t\tScannerOptions: migrate.ScannerOptions{\n\t\t\tMatchBegin:       true,\n\t\t\tBackslashEscapes: true,\n\t\t\tHashComments:     true,\n\t\t\t// The following are not support by MySQL/MariaDB.\n\t\t\tMatchBeginAtomic: false,\n\t\t\tMatchDollarQuote: false,\n\t\t},\n\t}).Scan(input)\n}\n\nfunc acquire(ctx context.Context, conn schema.ExecQuerier, name string, timeout time.Duration) error {\n\trows, err := conn.QueryContext(ctx, \"SELECT GET_LOCK(?, ?)\", name, int(timeout.Seconds()))\n\tif err != nil {\n\t\treturn err\n\t}\n\tswitch acquired, err := sqlx.ScanNullBool(rows); {\n\tcase err != nil:\n\t\treturn err\n\tcase !acquired.Valid:\n\t\t// NULL is returned in case of an unexpected internal error.\n\t\treturn fmt.Errorf(\"sql/mysql: unexpected internal error on Lock(%q, %s)\", name, timeout)\n\tcase !acquired.Bool:\n\t\treturn schema.ErrLocked\n\t}\n\treturn nil\n}\n\n// unescape strings with backslashes returned\n// for SQL expressions from information schema.\nfunc unescape(s string) string {\n\tvar b strings.Builder\n\tfor i := 0; i < len(s); i++ {\n\t\tswitch c := s[i]; {\n\t\tcase c != '\\\\' || i == len(s)-1:\n\t\t\tb.WriteByte(c)\n\t\tcase s[i+1] == '\\'', s[i+1] == '\\\\':\n\t\t\tb.WriteByte(s[i+1])\n\t\t\ti++\n\t\t}\n\t}\n\treturn b.String()\n}\n\ntype parser struct{}\n\n// ParseURL implements the sqlclient.URLParser interface.\nfunc (parser) ParseURL(u *url.URL) *sqlclient.URL {\n\tv := u.Query()\n\tv.Set(\"parseTime\", \"true\")\n\tu.RawQuery = v.Encode()\n\tcu := &sqlclient.URL{URL: u, DSN: dsn(u), Schema: strings.TrimPrefix(u.Path, \"/\")}\n\tif strings.HasSuffix(u.Scheme, \"+unix\") {\n\t\tcu.Schema = v.Get(\"database\")\n\t}\n\treturn cu\n}\n\n// ChangeSchema implements the sqlclient.SchemaChanger interface.\nfunc (parser) ChangeSchema(u *url.URL, s string) *url.URL {\n\tnu := *u\n\tnu.Path = \"/\" + s\n\treturn &nu\n}\n\n// dsn returns the MySQL standard DSN for opening\n// the sql.DB from the user provided URL.\nfunc dsn(u *url.URL) string {\n\tvar (\n\t\tb      strings.Builder\n\t\tvalues = u.Query()\n\t)\n\tb.WriteString(u.User.Username())\n\tif p, ok := u.User.Password(); ok {\n\t\tb.WriteByte(':')\n\t\tb.WriteString(p)\n\t}\n\tif b.Len() > 0 {\n\t\tb.WriteByte('@')\n\t}\n\tswitch {\n\tcase strings.HasSuffix(u.Scheme, \"+unix\"):\n\t\tb.WriteString(\"unix(\")\n\t\t// The path is always absolute, and\n\t\t// therefore the host should be empty.\n\t\tb.WriteString(u.Path)\n\t\tb.WriteString(\")/\")\n\t\tif name := values.Get(\"database\"); name != \"\" {\n\t\t\tb.WriteString(name)\n\t\t\tvalues.Del(\"database\")\n\t\t}\n\tdefault:\n\t\tif u.Host != \"\" {\n\t\t\tb.WriteString(\"tcp(\")\n\t\t\tb.WriteString(u.Host)\n\t\t\tb.WriteByte(')')\n\t\t}\n\t\tif u.Path != \"\" {\n\t\t\tb.WriteString(u.Path)\n\t\t} else {\n\t\t\tb.WriteByte('/')\n\t\t}\n\t}\n\tif p := values.Encode(); p != \"\" {\n\t\tb.WriteByte('?')\n\t\tb.WriteString(p)\n\t}\n\treturn b.String()\n}\n\n// MySQL standard column types as defined in its codebase. Name and order\n// is organized differently than MySQL.\n//\n// https://github.com/mysql/mysql-server/blob/8.0/include/field_types.h\n// https://github.com/mysql/mysql-server/blob/8.0/sql/dd/types/column.h\n// https://github.com/mysql/mysql-server/blob/8.0/sql/sql_show.cc\n// https://github.com/mysql/mysql-server/blob/8.0/sql/gis/geometries.cc\n// https://dev.mysql.com/doc/refman/8.0/en/other-vendor-data-types.html\nconst (\n\tTypeBool    = \"bool\"\n\tTypeBoolean = \"boolean\"\n\n\tTypeBit       = \"bit\"       // MYSQL_TYPE_BIT\n\tTypeInt       = \"int\"       // MYSQL_TYPE_LONG\n\tTypeTinyInt   = \"tinyint\"   // MYSQL_TYPE_TINY\n\tTypeSmallInt  = \"smallint\"  // MYSQL_TYPE_SHORT\n\tTypeMediumInt = \"mediumint\" // MYSQL_TYPE_INT24\n\tTypeBigInt    = \"bigint\"    // MYSQL_TYPE_LONGLONG\n\n\tTypeDecimal = \"decimal\" // MYSQL_TYPE_DECIMAL\n\tTypeNumeric = \"numeric\" // MYSQL_TYPE_DECIMAL (numeric_type rule in sql_yacc.yy)\n\tTypeFloat   = \"float\"   // MYSQL_TYPE_FLOAT\n\tTypeDouble  = \"double\"  // MYSQL_TYPE_DOUBLE\n\tTypeReal    = \"real\"    // MYSQL_TYPE_FLOAT or MYSQL_TYPE_DOUBLE (real_type in sql_yacc.yy)\n\n\tTypeTimestamp = \"timestamp\" // MYSQL_TYPE_TIMESTAMP\n\tTypeDate      = \"date\"      // MYSQL_TYPE_DATE\n\tTypeTime      = \"time\"      // MYSQL_TYPE_TIME\n\tTypeDateTime  = \"datetime\"  // MYSQL_TYPE_DATETIME\n\tTypeYear      = \"year\"      // MYSQL_TYPE_YEAR\n\n\tTypeVarchar    = \"varchar\"    // MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_VARCHAR\n\tTypeChar       = \"char\"       // MYSQL_TYPE_STRING\n\tTypeVarBinary  = \"varbinary\"  // MYSQL_TYPE_VAR_STRING + NULL CHARACTER_SET.\n\tTypeBinary     = \"binary\"     // MYSQL_TYPE_STRING + NULL CHARACTER_SET.\n\tTypeBlob       = \"blob\"       // MYSQL_TYPE_BLOB\n\tTypeTinyBlob   = \"tinyblob\"   // MYSQL_TYPE_TINYBLOB\n\tTypeMediumBlob = \"mediumblob\" // MYSQL_TYPE_MEDIUM_BLOB\n\tTypeLongBlob   = \"longblob\"   // MYSQL_TYPE_LONG_BLOB\n\tTypeText       = \"text\"       // MYSQL_TYPE_BLOB + CHARACTER_SET utf8mb4\n\tTypeTinyText   = \"tinytext\"   // MYSQL_TYPE_TINYBLOB + CHARACTER_SET utf8mb4\n\tTypeMediumText = \"mediumtext\" // MYSQL_TYPE_MEDIUM_BLOB + CHARACTER_SET utf8mb4\n\tTypeLongText   = \"longtext\"   // MYSQL_TYPE_LONG_BLOB with + CHARACTER_SET utf8mb4\n\n\tTypeEnum = \"enum\" // MYSQL_TYPE_ENUM\n\tTypeSet  = \"set\"  // MYSQL_TYPE_SET\n\tTypeJSON = \"json\" // MYSQL_TYPE_JSON\n\n\tTypeGeometry           = \"geometry\"           // MYSQL_TYPE_GEOMETRY\n\tTypePoint              = \"point\"              // Geometry_type::kPoint\n\tTypeMultiPoint         = \"multipoint\"         // Geometry_type::kMultipoint\n\tTypeLineString         = \"linestring\"         // Geometry_type::kLinestring\n\tTypeMultiLineString    = \"multilinestring\"    // Geometry_type::kMultilinestring\n\tTypePolygon            = \"polygon\"            // Geometry_type::kPolygon\n\tTypeMultiPolygon       = \"multipolygon\"       // Geometry_type::kMultipolygon\n\tTypeGeoCollection      = \"geomcollection\"     // Geometry_type::kGeometrycollection\n\tTypeGeometryCollection = \"geometrycollection\" // Geometry_type::kGeometrycollection\n\n\tTypeUUID = \"uuid\" // MariaDB supported uuid type from 10.7.0+\n\n\tTypeInet4 = \"inet4\" // MariaDB type for storage of IPv4 addresses, from 10.10.0+.\n\tTypeInet6 = \"inet6\" // MariaDB type for storage of IPv6 addresses, from 10.10.0+.\n)\n\n// Additional common constants in MySQL.\nconst (\n\tIndexTypeBTree    = \"BTREE\"\n\tIndexTypeHash     = \"HASH\"\n\tIndexTypeFullText = \"FULLTEXT\"\n\tIndexTypeSpatial  = \"SPATIAL\"\n\n\tIndexParserNGram = \"ngram\"\n\tIndexParserMeCab = \"mecab\"\n\n\tEngineInnoDB = \"InnoDB\"\n\tEngineMyISAM = \"MyISAM\"\n\tEngineMemory = \"Memory\"\n\tEngineCSV    = \"CSV\"\n\tEngineNDB    = \"NDB\" // NDBCLUSTER\n\n\tcurrentTS     = \"current_timestamp\"\n\tdefaultGen    = \"default_generated\"\n\tautoIncrement = \"auto_increment\"\n\n\tvirtual    = \"VIRTUAL\"\n\tstored     = \"STORED\"\n\tpersistent = \"PERSISTENT\"\n)\n\nfunc (*inspect) tablesQuery(context.Context) string {\n\treturn tablesQuery\n}\n\nfunc (*inspect) tablesQueryArgs(context.Context) string {\n\treturn tablesQueryArgs\n}\n\nfunc viewSpec(*schema.View) (*sqlspec.View, error) {\n\treturn nil, nil // unimplemented.\n}\n\nfunc convertView(*sqlspec.View, *schema.Schema) (*schema.View, error) {\n\treturn nil, nil // unimplemented.\n}\n\nfunc verifyChanges(context.Context, []schema.Change) error {\n\treturn nil // unimplemented.\n}\n"
  },
  {
    "path": "sql/mysql/driver_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysql\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/internal/sqltest\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestParser_ParseURL(t *testing.T) {\n\tt.Run(\"ParseTime\", func(t *testing.T) {\n\t\tu, err := url.Parse(\"mysql://user:pass@localhost:3306/my_db?foo=bar\")\n\t\trequire.NoError(t, err)\n\t\tac := parser{}.ParseURL(u)\n\t\trequire.Equal(t, \"true\", ac.Query().Get(\"parseTime\"))\n\t})\n\tt.Run(\"UnixDSN\", func(t *testing.T) {\n\t\tfor u, d := range map[string]string{\n\t\t\t\"mysql+unix:///path/to/socket\":                                    \"unix(/path/to/socket)/?parseTime=true\",\n\t\t\t\"mysql+unix://user:pass@/path/to/socket\":                          \"user:pass@unix(/path/to/socket)/?parseTime=true\",\n\t\t\t\"mysql+unix://user@/path/to/socket?database=dbname\":               \"user@unix(/path/to/socket)/dbname?parseTime=true\",\n\t\t\t\"maria+unix:///path/to/file.socket?database=test&tls=skip-verify\": \"unix(/path/to/file.socket)/test?parseTime=true&tls=skip-verify\",\n\t\t} {\n\t\t\tu1, err := url.Parse(u)\n\t\t\trequire.NoError(t, err)\n\t\t\tp := parser{}.ParseURL(u1)\n\t\t\trequire.Equal(t, d, p.DSN)\n\t\t}\n\t})\n\tt.Run(\"Schema\", func(t *testing.T) {\n\t\tfor u, d := range map[string]string{\n\t\t\t\"mysql://user:pass@localhost:3306/my_db?foo=bar\":    \"my_db\",\n\t\t\t\"mysql://user:pass@localhost:3306?foo=bar\":          \"\",\n\t\t\t\"mysql+unix:///path/to/socket\":                      \"\",\n\t\t\t\"mysql+unix://user:pass@/path/to/socket\":            \"\",\n\t\t\t\"mysql+unix://user@/path/to/socket?database=dbname\": \"dbname\",\n\t\t} {\n\t\t\tu1, err := url.Parse(u)\n\t\t\trequire.NoError(t, err)\n\t\t\tp := parser{}.ParseURL(u1)\n\t\t\trequire.Equal(t, d, p.Schema)\n\t\t}\n\t})\n}\n\nfunc TestDriver_LockAcquired(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tlock := func(l schema.Locker) {\n\t\tname, sec := \"name\", 1\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT GET_LOCK(?, ?)\")).\n\t\t\tWithArgs(name, sec).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"acquired\"}).AddRow(1)).\n\t\t\tRowsWillBeClosed()\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT RELEASE_LOCK(?)\")).\n\t\t\tWithArgs(name).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"released\"}).AddRow(1)).\n\t\t\tRowsWillBeClosed()\n\t\tunlock, err := l.Lock(context.Background(), name, time.Second)\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, unlock())\n\t}\n\n\tt.Run(\"OnPool\", func(t *testing.T) {\n\t\td := &Driver{conn: &conn{}}\n\t\td.ExecQuerier = &mockOpener{DB: db}\n\t\tlock(d)\n\t\trequire.EqualValues(t, 1, d.ExecQuerier.(*mockOpener).opened)\n\t})\n\n\tt.Run(\"OnConn\", func(t *testing.T) {\n\t\td := &Driver{conn: &conn{}}\n\t\tconn, err := db.Conn(context.Background())\n\t\trequire.NoError(t, err)\n\t\td.ExecQuerier = conn\n\t\tlock(d)\n\t})\n\n\tt.Run(\"OnTx\", func(t *testing.T) {\n\t\tm.ExpectBegin()\n\t\ttx, err := db.Begin()\n\t\trequire.NoError(t, err)\n\t\td := &Driver{conn: &conn{}}\n\t\td.ExecQuerier = tx\n\t\tlock(d)\n\t})\n\trequire.NoError(t, m.ExpectationsWereMet())\n}\n\nfunc TestDriver_LockError(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\td := &Driver{conn: &conn{}}\n\td.ExecQuerier = db\n\n\tt.Run(\"Timeout\", func(t *testing.T) {\n\t\tname, sec := \"name\", 60\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT GET_LOCK(?, ?)\")).\n\t\t\tWithArgs(name, sec).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"acquired\"}).AddRow(0)).\n\t\t\tRowsWillBeClosed()\n\t\tunlock, err := d.Lock(context.Background(), name, time.Minute)\n\t\trequire.Equal(t, schema.ErrLocked, err)\n\t\trequire.Nil(t, unlock)\n\t})\n\n\tt.Run(\"Internal\", func(t *testing.T) {\n\t\tname, sec := \"migrate\", -1\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT GET_LOCK(?, ?)\")).\n\t\t\tWithArgs(name, sec).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"acquired\"}).AddRow(nil)).\n\t\t\tRowsWillBeClosed()\n\t\tunlock, err := d.Lock(context.Background(), name, -time.Second)\n\t\trequire.EqualError(t, err, `sql/mysql: unexpected internal error on Lock(\"migrate\", -1s)`)\n\t\trequire.Nil(t, unlock)\n\t})\n}\n\nfunc TestDriver_UnlockError(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\td := &Driver{conn: &conn{ExecQuerier: db}}\n\tacquired := func(name string, sec int) {\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT GET_LOCK(?, ?)\")).\n\t\t\tWithArgs(name, sec).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"acquired\"}).AddRow(1)).\n\t\t\tRowsWillBeClosed()\n\t}\n\n\tt.Run(\"NotHeld\", func(t *testing.T) {\n\t\tname, sec := \"unknown_lock\", 0\n\t\tacquired(name, sec)\n\t\tunlock, err := d.Lock(context.Background(), name, time.Millisecond)\n\t\trequire.NoError(t, err)\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT RELEASE_LOCK(?)\")).\n\t\t\tWithArgs(name).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"released\"}).AddRow(0)).\n\t\t\tRowsWillBeClosed()\n\t\trequire.Error(t, unlock())\n\t})\n\n\tt.Run(\"Internal\", func(t *testing.T) {\n\t\tname, sec := \"unknown_error\", 1\n\t\tacquired(name, sec)\n\t\tunlock, err := d.Lock(context.Background(), name, time.Second+time.Millisecond)\n\t\trequire.NoError(t, err)\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT RELEASE_LOCK(?)\")).\n\t\t\tWithArgs(name).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"released\"}).AddRow(nil)).\n\t\t\tRowsWillBeClosed()\n\t\trequire.Error(t, unlock())\n\t})\n}\n\nfunc TestDriver_CheckClean(t *testing.T) {\n\ts := schema.New(\"test\")\n\tdrv := &Driver{Inspector: &mockInspector{schema: s}}\n\t// Empty schema.\n\terr := drv.CheckClean(context.Background(), nil)\n\trequire.NoError(t, err)\n\t// Revisions table found.\n\ts.AddTables(schema.NewTable(\"revisions\"))\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Name: \"revisions\", Schema: \"test\"})\n\trequire.NoError(t, err)\n\t// Multiple tables.\n\ts.Tables = []*schema.Table{schema.NewTable(\"a\"), schema.NewTable(\"revisions\")}\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Name: \"revisions\", Schema: \"test\"})\n\trequire.EqualError(t, err, `sql/migrate: connected database is not clean: found table \"a\" in schema \"test\"`)\n\n\tr := schema.NewRealm()\n\tdrv.Inspector = &mockInspector{realm: r}\n\t// Empty realm.\n\terr = drv.CheckClean(context.Background(), nil)\n\trequire.NoError(t, err)\n\t// Revisions table found.\n\ts.Tables = []*schema.Table{schema.NewTable(\"revisions\")}\n\tr.AddSchemas(s)\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Name: \"revisions\", Schema: \"test\"})\n\trequire.NoError(t, err)\n\t// Unknown table.\n\ts.Tables[0].Name = \"unknown\"\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Schema: \"test\", Name: \"revisions\"})\n\trequire.EqualError(t, err, `sql/migrate: connected database is not clean: found table \"unknown\"`)\n\t// Multiple tables.\n\ts.Tables = []*schema.Table{schema.NewTable(\"a\"), schema.NewTable(\"revisions\")}\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Schema: \"test\", Name: \"revisions\"})\n\trequire.EqualError(t, err, `sql/migrate: connected database is not clean: found multiple tables: 2`)\n}\n\nfunc TestDriver_Version(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmock{m}.version(\"8.0.13\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\n\ttype vr interface{ Version() string }\n\trequire.Implements(t, (*vr)(nil), drv)\n\trequire.Equal(t, \"8.0.13\", drv.(vr).Version())\n}\n\ntype mockInspector struct {\n\tschema.Inspector\n\trealm  *schema.Realm\n\tschema *schema.Schema\n}\n\nfunc (m *mockInspector) InspectSchema(context.Context, string, *schema.InspectOptions) (*schema.Schema, error) {\n\tif m.schema == nil {\n\t\treturn nil, &schema.NotExistError{}\n\t}\n\treturn m.schema, nil\n}\n\nfunc (m *mockInspector) InspectRealm(context.Context, *schema.InspectRealmOption) (*schema.Realm, error) {\n\treturn m.realm, nil\n}\n\ntype mockOpener struct {\n\t*sql.DB\n\topened uint\n}\n\nfunc (m *mockOpener) Conn(ctx context.Context) (*sql.Conn, error) {\n\tm.opened++\n\treturn m.DB.Conn(ctx)\n}\n"
  },
  {
    "path": "sql/mysql/inspect_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysql\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// A diff provides a MySQL implementation for schema.Inspector.\ntype inspect struct{ *conn }\n\nvar _ schema.Inspector = (*inspect)(nil)\n\n// InspectRealm returns schema descriptions of all resources in the given realm.\nfunc (i *inspect) InspectRealm(ctx context.Context, opts *schema.InspectRealmOption) (*schema.Realm, error) {\n\tschemas, err := i.schemas(ctx, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif opts == nil {\n\t\topts = &schema.InspectRealmOption{}\n\t}\n\tvar (\n\t\tmode = sqlx.ModeInspectRealm(opts)\n\t\tr    = schema.NewRealm(schemas...).SetCharset(i.charset).SetCollation(i.collate)\n\t)\n\tif len(schemas) > 0 {\n\t\tif mode.Is(schema.InspectTables) {\n\t\t\tif err := i.inspectTables(ctx, r, nil); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tsqlx.LinkSchemaTables(schemas)\n\t\t}\n\t}\n\treturn schema.ExcludeRealm(r, opts.Exclude)\n}\n\n// InspectSchema returns schema descriptions of the tables in the given schema.\n// If the schema name is empty, the result will be the attached schema.\nfunc (i *inspect) InspectSchema(ctx context.Context, name string, opts *schema.InspectOptions) (*schema.Schema, error) {\n\tschemas, err := i.schemas(ctx, &schema.InspectRealmOption{Schemas: []string{name}})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch n := len(schemas); {\n\tcase n == 0:\n\t\treturn nil, &schema.NotExistError{Err: fmt.Errorf(\"mysql: schema %q was not found\", name)}\n\tcase n > 1:\n\t\treturn nil, fmt.Errorf(\"mysql: %d schemas were found for %q\", n, name)\n\t}\n\tif opts == nil {\n\t\topts = &schema.InspectOptions{}\n\t}\n\tvar (\n\t\tmode = sqlx.ModeInspectSchema(opts)\n\t\tr    = schema.NewRealm(schemas...).SetCharset(i.charset).SetCollation(i.collate)\n\t)\n\tif mode.Is(schema.InspectTables) {\n\t\tif err := i.inspectTables(ctx, r, opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsqlx.LinkSchemaTables(schemas)\n\t}\n\treturn schema.ExcludeSchema(r.Schemas[0], opts.Exclude)\n}\n\nfunc (i *inspect) inspectTables(ctx context.Context, r *schema.Realm, opts *schema.InspectOptions) error {\n\tif err := i.tables(ctx, r, opts); err != nil {\n\t\treturn err\n\t}\n\tfor _, s := range r.Schemas {\n\t\tif len(s.Tables) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif err := i.columns(ctx, s); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := i.indexes(ctx, s); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := i.fks(ctx, s); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := i.checks(ctx, s); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := i.showCreate(ctx, s); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// schemas returns the list of the schemas in the database.\nfunc (i *inspect) schemas(ctx context.Context, opts *schema.InspectRealmOption) ([]*schema.Schema, error) {\n\tvar (\n\t\targs  []any\n\t\tquery = schemasQuery\n\t)\n\tif opts != nil {\n\t\tswitch n := len(opts.Schemas); {\n\t\tcase n == 1 && opts.Schemas[0] == \"\":\n\t\t\tquery = fmt.Sprintf(schemasQueryArgs, \"= SCHEMA()\")\n\t\tcase n == 1 && opts.Schemas[0] != \"\":\n\t\t\tquery = fmt.Sprintf(schemasQueryArgs, \"= ?\")\n\t\t\targs = append(args, opts.Schemas[0])\n\t\tcase n > 0:\n\t\t\tquery = fmt.Sprintf(schemasQueryArgs, \"IN (\"+nArgs(len(opts.Schemas))+\")\")\n\t\t\tfor _, s := range opts.Schemas {\n\t\t\t\targs = append(args, s)\n\t\t\t}\n\t\t}\n\t}\n\trows, err := i.QueryContext(ctx, query, args...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"mysql: querying schemas: %w\", err)\n\t}\n\tdefer rows.Close()\n\tvar schemas []*schema.Schema\n\tfor rows.Next() {\n\t\tvar name, charset, collation string\n\t\tif err := rows.Scan(&name, &charset, &collation); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tschemas = append(schemas, &schema.Schema{\n\t\t\tName: name,\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Charset{\n\t\t\t\t\tV: charset,\n\t\t\t\t},\n\t\t\t\t&schema.Collation{\n\t\t\t\t\tV: collation,\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\treturn schemas, nil\n}\n\nfunc (i *inspect) tables(ctx context.Context, realm *schema.Realm, opts *schema.InspectOptions) error {\n\tvar (\n\t\targs  []any\n\t\tquery = fmt.Sprintf(i.tablesQuery(ctx), nArgs(len(realm.Schemas)))\n\t)\n\tfor _, s := range realm.Schemas {\n\t\targs = append(args, s.Name)\n\t}\n\tif opts != nil && len(opts.Tables) > 0 {\n\t\tfor _, t := range opts.Tables {\n\t\t\targs = append(args, t)\n\t\t}\n\t\tquery = fmt.Sprintf(i.tablesQueryArgs(ctx), nArgs(len(realm.Schemas)), nArgs(len(opts.Tables)))\n\t}\n\trows, err := i.QueryContext(ctx, query, args...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tdefaultE                                                          sql.NullBool\n\t\t\tautoinc                                                           sql.NullInt64\n\t\t\ttSchema, name, charset, collation, comment, options, engine, ttyp sql.NullString\n\t\t)\n\t\tif err := rows.Scan(&tSchema, &name, &charset, &collation, &autoinc, &comment, &options, &engine, &defaultE, &ttyp); err != nil {\n\t\t\treturn fmt.Errorf(\"scan table information: %w\", err)\n\t\t}\n\t\tif !sqlx.ValidString(tSchema) || !sqlx.ValidString(name) {\n\t\t\treturn fmt.Errorf(\"invalid schema or table name: %q.%q\", tSchema.String, name.String)\n\t\t}\n\t\ts, ok := realm.Schema(tSchema.String)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"schema %q was not found in realm\", tSchema.String)\n\t\t}\n\t\tt := schema.NewTable(name.String)\n\t\ts.AddTables(t)\n\t\tif sqlx.ValidString(charset) {\n\t\t\tt.Attrs = append(t.Attrs, &schema.Charset{\n\t\t\t\tV: charset.String,\n\t\t\t})\n\t\t}\n\t\tif sqlx.ValidString(collation) {\n\t\t\tt.Attrs = append(t.Attrs, &schema.Collation{\n\t\t\t\tV: collation.String,\n\t\t\t})\n\t\t}\n\t\tif sqlx.ValidString(comment) {\n\t\t\tt.Attrs = append(t.Attrs, &schema.Comment{\n\t\t\t\tText: comment.String,\n\t\t\t})\n\t\t}\n\t\tif sqlx.ValidString(options) {\n\t\t\tt.Attrs = append(t.Attrs, &CreateOptions{\n\t\t\t\tV: options.String,\n\t\t\t})\n\t\t}\n\t\tif sqlx.ValidString(engine) && defaultE.Valid {\n\t\t\tt.Attrs = append(t.Attrs, &Engine{\n\t\t\t\tV:       engine.String,\n\t\t\t\tDefault: defaultE.Bool,\n\t\t\t})\n\t\t}\n\t\tif autoinc.Valid {\n\t\t\tt.Attrs = append(t.Attrs, &AutoIncrement{\n\t\t\t\tV: autoinc.Int64,\n\t\t\t})\n\t\t}\n\t}\n\treturn rows.Err()\n}\n\n// columns queries and appends the columns of the given table.\nfunc (i *inspect) columns(ctx context.Context, s *schema.Schema) error {\n\tquery := columnsQuery\n\tif i.SupportsGeneratedColumns() {\n\t\tquery = columnsExprQuery\n\t}\n\trows, err := i.querySchema(ctx, query, s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"mysql: query schema %q columns: %w\", s.Name, err)\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tif err := i.addColumn(s, rows); err != nil {\n\t\t\treturn fmt.Errorf(\"mysql: %w\", err)\n\t\t}\n\t}\n\treturn rows.Err()\n}\n\n// addColumn scans the current row and adds a new column from it to the table.\nfunc (i *inspect) addColumn(s *schema.Schema, rows *sql.Rows) error {\n\tvar table, name, typ, comment, nullable, key, defaults, extra, charset, collation, expr sql.NullString\n\tif err := rows.Scan(&table, &name, &typ, &comment, &nullable, &key, &defaults, &extra, &charset, &collation, &expr); err != nil {\n\t\treturn err\n\t}\n\tt, ok := s.Table(table.String)\n\tif !ok {\n\t\treturn fmt.Errorf(\"table %q was not found in schema\", table.String)\n\t}\n\tc := &schema.Column{\n\t\tName: name.String,\n\t\tType: &schema.ColumnType{\n\t\t\tRaw:  typ.String,\n\t\t\tNull: nullable.String == \"YES\",\n\t\t},\n\t}\n\tct, err := ParseType(c.Type.Raw)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse %q.%q type %q: %w\", t.Name, c.Name, c.Type.Raw, err)\n\t}\n\tc.Type.Type = ct\n\tattr, err := parseExtra(extra.String)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif attr.autoinc {\n\t\ta := &AutoIncrement{}\n\t\tif !sqlx.Has(t.Attrs, a) {\n\t\t\t// A table can have only one AUTO_INCREMENT column. If it was returned as NULL\n\t\t\t// from INFORMATION_SCHEMA, it is due to information_schema_stats_expiry, and\n\t\t\t// we need to extract it from the 'CREATE TABLE' command.\n\t\t\tputShow(t).auto = a\n\t\t}\n\t\tc.Attrs = append(c.Attrs, a)\n\t}\n\tif attr.onUpdate != \"\" {\n\t\tc.Attrs = append(c.Attrs, &OnUpdate{A: attr.onUpdate})\n\t}\n\tif x := expr.String; x != \"\" {\n\t\tif !i.Maria() {\n\t\t\tx = unescape(x)\n\t\t}\n\t\tc.SetGeneratedExpr(&schema.GeneratedExpr{Expr: x, Type: attr.generatedType})\n\t}\n\tif defaults.Valid {\n\t\tif i.Maria() {\n\t\t\tc.Default = i.marDefaultExpr(c, defaults.String)\n\t\t} else {\n\t\t\tc.Default = i.myDefaultExpr(c, defaults.String, attr)\n\t\t}\n\t}\n\tif sqlx.ValidString(comment) {\n\t\tc.SetComment(comment.String)\n\t}\n\tif sqlx.ValidString(charset) {\n\t\tc.SetCharset(charset.String)\n\t}\n\tif sqlx.ValidString(collation) {\n\t\tc.SetCollation(collation.String)\n\t}\n\tt.AddColumns(c)\n\treturn nil\n}\n\n// indexes queries and appends the indexes of the given table.\nfunc (i *inspect) indexes(ctx context.Context, s *schema.Schema) error {\n\tquery := i.indexQuery()\n\trows, err := i.querySchema(ctx, query, s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"mysql: query schema %q indexes: %w\", s.Name, err)\n\t}\n\tdefer rows.Close()\n\tif err := i.addIndexes(s, rows); err != nil {\n\t\treturn err\n\t}\n\treturn rows.Err()\n}\n\n// addIndexes scans the rows and adds the indexes to the table.\nfunc (i *inspect) addIndexes(s *schema.Schema, rows *sql.Rows) error {\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tseqno                          int\n\t\t\ttable, name, indexType         string\n\t\t\tnonuniq, desc                  sql.NullBool\n\t\t\tcolumn, subPart, expr, comment sql.NullString\n\t\t)\n\t\tif err := rows.Scan(&table, &name, &column, &nonuniq, &seqno, &indexType, &desc, &comment, &subPart, &expr); err != nil {\n\t\t\treturn fmt.Errorf(\"mysql: scanning indexes for schema %q: %w\", s.Name, err)\n\t\t}\n\t\tt, ok := s.Table(table)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"table %q was not found in schema\", table)\n\t\t}\n\t\tvar idx *schema.Index\n\t\tswitch {\n\t\t// Primary key.\n\t\tcase name == \"PRIMARY\":\n\t\t\tif idx = t.PrimaryKey; idx == nil {\n\t\t\t\tidx = schema.NewIndex(\"PRI\").\n\t\t\t\t\tAddAttrs(&IndexType{T: indexType})\n\t\t\t\tt.PrimaryKey = idx\n\t\t\t}\n\t\tdefault:\n\t\t\tif idx, ok = t.Index(name); !ok {\n\t\t\t\tidx = schema.NewIndex(name).\n\t\t\t\t\tSetUnique(!nonuniq.Bool).\n\t\t\t\t\tAddAttrs(&IndexType{T: indexType})\n\t\t\t\tif indexType == IndexTypeFullText {\n\t\t\t\t\tputShow(t).addFullText(idx)\n\t\t\t\t}\n\t\t\t\tif sqlx.ValidString(comment) {\n\t\t\t\t\tidx.SetComment(comment.String)\n\t\t\t\t}\n\t\t\t\tt.AddIndexes(idx)\n\t\t\t}\n\t\t}\n\t\t// Rows are ordered by SEQ_IN_INDEX that specifies the\n\t\t// position of the column in the index definition.\n\t\tpart := &schema.IndexPart{SeqNo: seqno, Desc: desc.Bool}\n\t\tswitch {\n\t\tcase sqlx.ValidString(expr):\n\t\t\tpart.X = &schema.RawExpr{X: unescape(expr.String)}\n\t\tcase sqlx.ValidString(column):\n\t\t\tpart.C, ok = t.Column(column.String)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"mysql: column %q was not found for index %q\", column.String, idx.Name)\n\t\t\t}\n\t\t\tif sqlx.ValidString(subPart) && indexType != IndexTypeSpatial {\n\t\t\t\tn, err := strconv.Atoi(subPart.String)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"mysql: parse index prefix size %q: %w\", subPart.String, err)\n\t\t\t\t}\n\t\t\t\tpart.Attrs = append(part.Attrs, &SubPart{\n\t\t\t\t\tLen: n,\n\t\t\t\t})\n\t\t\t}\n\t\t\tpart.C.Indexes = append(part.C.Indexes, idx)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"mysql: invalid part for index %q\", idx.Name)\n\t\t}\n\t\tidx.Parts = append(idx.Parts, part)\n\t}\n\treturn nil\n}\n\n// fks queries and appends the foreign keys of the given table.\nfunc (i *inspect) fks(ctx context.Context, s *schema.Schema) error {\n\trows, err := i.querySchema(ctx, fksQuery, s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"mysql: querying %q foreign keys: %w\", s.Name, err)\n\t}\n\tdefer rows.Close()\n\tif err := sqlx.SchemaFKs(s, rows); err != nil {\n\t\treturn fmt.Errorf(\"mysql: %w\", err)\n\t}\n\treturn rows.Err()\n}\n\n// checks queries and appends the check constraints of the given table.\nfunc (i *inspect) checks(ctx context.Context, s *schema.Schema) error {\n\tquery, ok := i.supportsCheck()\n\tif !ok {\n\t\treturn nil\n\t}\n\trows, err := i.querySchema(ctx, query, s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"mysql: querying %q check constraints: %w\", s.Name, err)\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar table, name, clause, enforced sql.NullString\n\t\tif err := rows.Scan(&table, &name, &clause, &enforced); err != nil {\n\t\t\treturn fmt.Errorf(\"mysql: %w\", err)\n\t\t}\n\t\tt, ok := s.Table(table.String)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"table %q was not found in schema\", table.String)\n\t\t}\n\t\tcheck := &schema.Check{\n\t\t\tName: name.String,\n\t\t\tExpr: unescape(clause.String),\n\t\t}\n\t\tif i.Maria() {\n\t\t\tcheck.Expr = clause.String\n\t\t\t// In MariaDB, JSON is an alias to LONGTEXT. For versions >= 10.4.3, the CHARSET and COLLATE set to utf8mb4\n\t\t\t// and a CHECK constraint is automatically created for the column as well (i.e. JSON_VALID(`<C>`)). However,\n\t\t\t// we expect tools like Atlas and Ent to manually add this CHECK for older versions of MariaDB.\n\t\t\tc, ok := t.Column(check.Name)\n\t\t\tif ok && c.Type.Raw == TypeLongText && check.Expr == fmt.Sprintf(\"json_valid(`%s`)\", c.Name) {\n\t\t\t\tc.Type.Raw = TypeJSON\n\t\t\t\tc.Type.Type = &schema.JSONType{T: TypeJSON}\n\t\t\t\t// Unset the inspected CHARSET/COLLATE attributes\n\t\t\t\t// as they are valid only for character types.\n\t\t\t\tc.UnsetCharset().UnsetCollation()\n\t\t\t\t// Skip adding this CHECK constraint to the table definition\n\t\t\t\t// as it is implicitly created by MariaDB for this JSON column.\n\t\t\t\tcontinue\n\t\t\t}\n\t\t} else if enforced.String == \"NO\" {\n\t\t\t// The ENFORCED attribute is not supported by MariaDB.\n\t\t\t// Also, skip adding it in case the CHECK is ENFORCED,\n\t\t\t// as the default is ENFORCED if not state otherwise.\n\t\t\tcheck.Attrs = append(check.Attrs, &Enforced{V: false})\n\t\t}\n\t\tt.Attrs = append(t.Attrs, check)\n\t}\n\treturn rows.Err()\n}\n\n// supportsCheck reports if the connected database supports\n// the CHECK clause, and return the querying for getting them.\nfunc (i *inspect) supportsCheck() (string, bool) {\n\tq := myChecksQuery\n\tif i.Maria() {\n\t\tq = marChecksQuery\n\t}\n\treturn q, i.SupportsCheck()\n}\n\n// indexQuery returns the query to retrieve the indexes of the given table.\nfunc (i *inspect) indexQuery() string {\n\tquery := indexesNoCommentQuery\n\tif i.SupportsIndexComment() {\n\t\tquery = indexesQuery\n\t}\n\tif i.SupportsIndexExpr() {\n\t\tquery = indexesExprQuery\n\t}\n\treturn query\n}\n\n// extraAttr is a parsed version of the information_schema EXTRA column.\ntype extraAttr struct {\n\tautoinc          bool\n\tonUpdate         string\n\tgeneratedType    string\n\tdefaultGenerated bool\n}\n\nvar (\n\treGenerateType = regexp.MustCompile(`(?i)^(stored|persistent|virtual) generated$`)\n\treTimeOnUpdate = regexp.MustCompile(`(?i)^(?:default_generated )?on update (current_timestamp(?:\\(\\d?\\))?)$`)\n)\n\n// parseExtra returns a parsed version of the EXTRA column\n// from the INFORMATION_SCHEMA.COLUMNS table.\nfunc parseExtra(extra string) (*extraAttr, error) {\n\tattr := &extraAttr{}\n\tswitch el := strings.ToLower(extra); {\n\tcase el == \"\", el == \"null\":\n\tcase el == defaultGen:\n\t\tattr.defaultGenerated = true\n\t\t// The column has an expression default value,\n\t\t// and it is handled in Driver.addColumn.\n\tcase el == autoIncrement:\n\t\tattr.autoinc = true\n\tcase reTimeOnUpdate.MatchString(extra):\n\t\tattr.onUpdate = reTimeOnUpdate.FindStringSubmatch(extra)[1]\n\tcase reGenerateType.MatchString(extra):\n\t\tattr.generatedType = reGenerateType.FindStringSubmatch(extra)[1]\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown extra column attribute %q\", extra)\n\t}\n\treturn attr, nil\n}\n\n// showCreate sets and fixes schema elements that require information from\n// the 'SHOW CREATE' command.\nfunc (i *inspect) showCreate(ctx context.Context, s *schema.Schema) error {\n\tfor _, t := range s.Tables {\n\t\tst, ok := popShow(t)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tc, err := i.createStmt(ctx, t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tst.setIndexParser(c)\n\t\tif err := st.setAutoInc(t, c); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nvar reAutoinc = regexp.MustCompile(`(?i)\\s*AUTO_INCREMENT\\s*=\\s*(\\d+)\\s*`)\n\n// createStmt loads the CREATE TABLE statement for the table.\nfunc (i *inspect) createStmt(ctx context.Context, t *schema.Table) (*CreateStmt, error) {\n\tc := &CreateStmt{}\n\tb := &sqlx.Builder{QuoteOpening: '`', QuoteClosing: '`'}\n\trows, err := i.QueryContext(ctx, b.P(\"SHOW CREATE TABLE\").Table(t).String())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"query CREATE TABLE %q: %w\", t.Name, err)\n\t}\n\tif err := sqlx.ScanOne(rows, &sql.NullString{}, &c.S); err != nil {\n\t\treturn nil, fmt.Errorf(\"scan CREATE TABLE %q: %w\", t.Name, err)\n\t}\n\tt.Attrs = append(t.Attrs, c)\n\treturn c, nil\n}\n\nvar reCurrTimestamp = regexp.MustCompile(`(?i)^current_timestamp(?:\\(\\d?\\))?$`)\n\n// myDefaultExpr returns the correct schema.Expr based on the column attributes for MySQL.\nfunc (i *inspect) myDefaultExpr(c *schema.Column, x string, attr *extraAttr) schema.Expr {\n\t// In MySQL, the DEFAULT_GENERATED indicates the column has an expression default value.\n\tif i.SupportsExprDefault() && attr.defaultGenerated {\n\t\t// Skip CURRENT_TIMESTAMP, because wrapping it with parens will translate it to now().\n\t\tif _, ok := c.Type.Type.(*schema.TimeType); ok && reCurrTimestamp.MatchString(x) {\n\t\t\treturn &schema.RawExpr{X: x}\n\t\t}\n\t\treturn &schema.RawExpr{X: sqlx.MayWrap(unescape(x))}\n\t}\n\tswitch c.Type.Type.(type) {\n\tcase *schema.BinaryType:\n\t\t// MySQL v8 uses Hexadecimal representation.\n\t\tif isHex(x) {\n\t\t\treturn &schema.Literal{V: x}\n\t\t}\n\tcase *BitType, *schema.BoolType, *schema.IntegerType, *schema.DecimalType, *schema.FloatType:\n\t\treturn &schema.Literal{V: x}\n\tcase *schema.TimeType:\n\t\t// \"current_timestamp\" is exceptional in old versions\n\t\t// of MySQL for timestamp and datetime data types.\n\t\tif reCurrTimestamp.MatchString(x) {\n\t\t\treturn &schema.RawExpr{X: x}\n\t\t}\n\t}\n\treturn &schema.Literal{V: quote(x)}\n}\n\n// parseColumn returns column parts, size and signed-info from a MySQL type.\nfunc parseColumn(typ string) (parts []string, size int, unsigned bool, err error) {\n\t// Remove MariaDB like comments embedded in the type\n\t// for compatibility. For example: /* mariadb-5.3 */.\n\tif i := strings.Index(typ, \"/*\"); i > 0 && strings.HasSuffix(strings.TrimSpace(typ), \"*/\") {\n\t\ttyp = strings.TrimSpace(typ[:i])\n\t}\n\tif parts = strings.FieldsFunc(typ, func(r rune) bool {\n\t\treturn r == '(' || r == ')' || r == ' ' || r == ','\n\t}); len(parts) == 0 {\n\t\treturn nil, 0, false, fmt.Errorf(\"unexpected or empty type %q\", typ)\n\t}\n\tswitch parts[0] {\n\tcase TypeBit, TypeBinary, TypeVarBinary, TypeChar, TypeVarchar:\n\tcase TypeTinyInt, TypeSmallInt, TypeMediumInt, TypeInt, TypeBigInt,\n\t\tTypeDecimal, TypeNumeric, TypeFloat, TypeDouble, TypeReal:\n\t\tif attr := parts[len(parts)-1]; attr == \"unsigned\" || attr == \"zerofill\" {\n\t\t\tunsigned = true\n\t\t}\n\t}\n\tif len(parts) > 1 && sqlx.IsUint(parts[1]) {\n\t\tsize, err = strconv.Atoi(parts[1])\n\t}\n\tif err != nil {\n\t\treturn nil, 0, false, fmt.Errorf(\"parse %q to int: %w\", parts[1], err)\n\t}\n\treturn parts, size, unsigned, nil\n}\n\n// hasNumericDefault reports if the given type has a numeric default value.\nfunc hasNumericDefault(t schema.Type) bool {\n\tswitch t.(type) {\n\tcase *BitType, *schema.BoolType, *schema.IntegerType, *schema.DecimalType, *schema.FloatType:\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc isHex(x string) bool { return len(x) > 2 && strings.ToLower(x[:2]) == \"0x\" }\n\n// marDefaultExpr returns the correct schema.Expr based on the column attributes for MariaDB.\nfunc (i *inspect) marDefaultExpr(c *schema.Column, x string) schema.Expr {\n\t// Unlike MySQL, NULL means default to NULL or no default.\n\tif x == \"NULL\" {\n\t\treturn nil\n\t}\n\t// From MariaDB 10.2.7, string-based literals are quoted to distinguish them from expressions.\n\tif i.GTE(\"10.2.7\") && sqlx.IsQuoted(x, '\\'') {\n\t\treturn &schema.Literal{V: x}\n\t}\n\t// In this case, we need to manually check if the expression is literal, or fallback to raw expression.\n\tswitch c.Type.Type.(type) {\n\tcase *BitType:\n\t\t// Bit literal values. See https://mariadb.com/kb/en/binary-literals.\n\t\tif strings.HasPrefix(x, \"b'\") && strings.HasSuffix(x, \"'\") {\n\t\t\treturn &schema.Literal{V: x}\n\t\t}\n\tcase *schema.BoolType, *schema.IntegerType, *schema.DecimalType, *schema.FloatType:\n\t\tif _, err := strconv.ParseFloat(x, 64); err == nil {\n\t\t\treturn &schema.Literal{V: x}\n\t\t}\n\tcase *schema.TimeType:\n\t\t// \"current_timestamp\" is exceptional in old versions\n\t\t// of MySQL (i.e. MariaDB in this case).\n\t\tif strings.ToLower(x) == currentTS {\n\t\t\treturn &schema.RawExpr{X: x}\n\t\t}\n\t}\n\tif !i.SupportsExprDefault() {\n\t\treturn &schema.Literal{V: quote(x)}\n\t}\n\treturn &schema.RawExpr{X: sqlx.MayWrap(x)}\n}\n\nfunc (i *inspect) querySchema(ctx context.Context, query string, s *schema.Schema) (*sql.Rows, error) {\n\t// Number of times the schema name is parameterized.\n\targs := make([]any, strings.Count(query, \"?\"))\n\tfor i := range args {\n\t\targs[i] = s.Name\n\t}\n\tfor _, t := range s.Tables {\n\t\targs = append(args, t.Name)\n\t}\n\treturn i.QueryContext(ctx, fmt.Sprintf(query, nArgs(len(s.Tables))), args...)\n}\n\nfunc nArgs(n int) string { return strings.Repeat(\"?, \", n-1) + \"?\" }\n\nconst (\n\t// Query to list system variables.\n\tvariablesQuery = \"SELECT @@version, @@collation_server, @@character_set_server, @@lower_case_table_names\"\n\n\t// Query to list database schemas.\n\tschemasQuery = \"SELECT `SCHEMA_NAME`, `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME` from `INFORMATION_SCHEMA`.`SCHEMATA` WHERE `SCHEMA_NAME` NOT IN ('information_schema','innodb','mysql','performance_schema','sys') ORDER BY `SCHEMA_NAME`\"\n\n\t// Query to list specific database schemas.\n\tschemasQueryArgs = \"SELECT `SCHEMA_NAME`, `DEFAULT_CHARACTER_SET_NAME`, `DEFAULT_COLLATION_NAME` from `INFORMATION_SCHEMA`.`SCHEMATA` WHERE `SCHEMA_NAME` %s ORDER BY `SCHEMA_NAME`\"\n\n\t// Query to list table columns.\n\tcolumnsQuery     = \"SELECT `TABLE_NAME`, `COLUMN_NAME`, `COLUMN_TYPE`, `COLUMN_COMMENT`, `IS_NULLABLE`, `COLUMN_KEY`, `COLUMN_DEFAULT`, `EXTRA`, `CHARACTER_SET_NAME`, `COLLATION_NAME`, NULL AS `GENERATION_EXPRESSION` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` IN (%s) ORDER BY `ORDINAL_POSITION`\"\n\tcolumnsExprQuery = \"SELECT `TABLE_NAME`, `COLUMN_NAME`, `COLUMN_TYPE`, `COLUMN_COMMENT`, `IS_NULLABLE`, `COLUMN_KEY`, `COLUMN_DEFAULT`, `EXTRA`, `CHARACTER_SET_NAME`, `COLLATION_NAME`, `GENERATION_EXPRESSION` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` IN (%s) ORDER BY `ORDINAL_POSITION`\"\n\n\t// Query to list table indexes.\n\tindexesQuery          = \"SELECT `TABLE_NAME`, `INDEX_NAME`, `COLUMN_NAME`, `NON_UNIQUE`, `SEQ_IN_INDEX`, `INDEX_TYPE`, UPPER(`COLLATION`) = 'D' AS `DESC`, `INDEX_COMMENT`, `SUB_PART`, NULL AS `EXPRESSION` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` IN (%s) ORDER BY `index_name`, `seq_in_index`\"\n\tindexesExprQuery      = \"SELECT `TABLE_NAME`, `INDEX_NAME`, `COLUMN_NAME`, `NON_UNIQUE`, `SEQ_IN_INDEX`, `INDEX_TYPE`, UPPER(`COLLATION`) = 'D' AS `DESC`, `INDEX_COMMENT`, `SUB_PART`, `EXPRESSION` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` IN (%s) ORDER BY `index_name`, `seq_in_index`\"\n\tindexesNoCommentQuery = \"SELECT `TABLE_NAME`, `INDEX_NAME`, `COLUMN_NAME`, `NON_UNIQUE`, `SEQ_IN_INDEX`, `INDEX_TYPE`, UPPER(`COLLATION`) = 'D' AS `DESC`, NULL AS `INDEX_COMMENT`, `SUB_PART`, NULL AS `EXPRESSION` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` IN (%s) ORDER BY `index_name`, `seq_in_index`\"\n\n\ttablesQuery = `\nSELECT\n\tt1.TABLE_SCHEMA,\n\tt1.TABLE_NAME,\n\tt2.CHARACTER_SET_NAME,\n\tt1.TABLE_COLLATION,\n\tt1.AUTO_INCREMENT,\n\tt1.TABLE_COMMENT,\n\tt1.CREATE_OPTIONS,\n\tt1.ENGINE,\n\tt3.SUPPORT = 'DEFAULT' AS DEFAULT_ENGINE,\n\tt1.TABLE_TYPE\nFROM\n\tINFORMATION_SCHEMA.TABLES AS t1\n\tLEFT JOIN INFORMATION_SCHEMA.COLLATIONS AS t2\n\tON t1.TABLE_COLLATION = t2.COLLATION_NAME\n\tLEFT JOIN INFORMATION_SCHEMA.ENGINES AS t3\n\tON t1.ENGINE = t3.ENGINE\nWHERE\n\tTABLE_SCHEMA IN (%s)\n\tAND TABLE_TYPE = 'BASE TABLE'\nORDER BY\n\tTABLE_SCHEMA, TABLE_NAME`\n\n\ttablesQueryArgs = `\nSELECT\n\tt1.TABLE_SCHEMA,\n\tt1.TABLE_NAME,\n\tt2.CHARACTER_SET_NAME,\n\tt1.TABLE_COLLATION,\n\tt1.AUTO_INCREMENT,\n\tt1.TABLE_COMMENT,\n\tt1.CREATE_OPTIONS,\n\tt1.ENGINE,\n\tt3.SUPPORT = 'DEFAULT' AS DEFAULT_ENGINE,\n\tt1.TABLE_TYPE\nFROM\n\tINFORMATION_SCHEMA.TABLES AS t1\n\tJOIN INFORMATION_SCHEMA.COLLATIONS AS t2\n\tON t1.TABLE_COLLATION = t2.COLLATION_NAME\n\tLEFT JOIN INFORMATION_SCHEMA.ENGINES AS t3\n\tON t1.ENGINE = t3.ENGINE\nWHERE\n\tTABLE_SCHEMA IN (%s)\n\tAND TABLE_NAME IN (%s)\n\tAND TABLE_TYPE = 'BASE TABLE'\nORDER BY\n\tTABLE_SCHEMA, TABLE_NAME`\n\n\t// Query to list table check constraints.\n\tmyChecksQuery = `\nSELECT\n\tt1.TABLE_NAME,\n\tt1.CONSTRAINT_NAME,\n\tt2.CHECK_CLAUSE,\n\tt1.ENFORCED\nFROM\n\tINFORMATION_SCHEMA.TABLE_CONSTRAINTS AS t1\n\tJOIN INFORMATION_SCHEMA.CHECK_CONSTRAINTS AS t2\n\tON t1.CONSTRAINT_NAME = t2.CONSTRAINT_NAME\n\tAND t1.CONSTRAINT_SCHEMA = t2.CONSTRAINT_SCHEMA\nWHERE\n\tt1.CONSTRAINT_TYPE = 'CHECK'\n\tAND t1.TABLE_SCHEMA = ?\n\tAND t1.TABLE_NAME IN (%s)\nORDER BY\n\tt1.TABLE_NAME, t1.CONSTRAINT_NAME\n`\n\n\tmarChecksQuery = `\nSELECT\n\tTABLE_NAME,\n\tCONSTRAINT_NAME,\n\tCHECK_CLAUSE,\n\t\"YES\" AS ENFORCED\nFROM\n\tINFORMATION_SCHEMA.CHECK_CONSTRAINTS\nWHERE\n\tCONSTRAINT_SCHEMA = ?\n\tAND TABLE_NAME IN (%s)\nORDER BY\n\tTABLE_NAME, CONSTRAINT_NAME\n`\n\t// Query to list table foreign keys.\n\tfksQuery = `\nSELECT\n\tt1.CONSTRAINT_NAME,\n\tt1.TABLE_NAME,\n\tt1.COLUMN_NAME,\n\tt1.TABLE_SCHEMA,\n\tt1.REFERENCED_TABLE_NAME,\n\tt1.REFERENCED_COLUMN_NAME,\n\tt1.REFERENCED_TABLE_SCHEMA,\n\tt2.UPDATE_RULE,\n\tt2.DELETE_RULE\nFROM\n\tINFORMATION_SCHEMA.KEY_COLUMN_USAGE AS t1\n\tJOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS t2\n\tON t1.CONSTRAINT_NAME = t2.CONSTRAINT_NAME\nWHERE\n\tt1.REFERENCED_COLUMN_NAME IS NOT NULL\n\tAND BINARY t1.TABLE_SCHEMA = ?\n\tAND BINARY t2.CONSTRAINT_SCHEMA = ?\n\tAND t1.TABLE_NAME IN (%s)\nORDER BY\n\tBINARY t1.TABLE_NAME,\n\tBINARY t1.CONSTRAINT_NAME,\n\tt1.ORDINAL_POSITION`\n)\n\ntype (\n\t// AutoIncrement attribute for columns with \"AUTO_INCREMENT\" as a default.\n\t// V represent an optional start value for the counter.\n\tAutoIncrement struct {\n\t\tschema.Attr\n\t\tV int64\n\t}\n\n\t// CreateOptions attribute for describing extra options used with CREATE TABLE.\n\tCreateOptions struct {\n\t\tschema.Attr\n\t\tV string\n\t}\n\n\t// CreateStmt describes the SQL statement used to create a table.\n\tCreateStmt struct {\n\t\tschema.Attr\n\t\tS string\n\t}\n\n\t// Engine attribute describes the storage engine used to create a table.\n\tEngine struct {\n\t\tschema.Attr\n\t\tV       string // InnoDB, MyISAM, etc.\n\t\tDefault bool   // The default engine used by the server.\n\t}\n\n\t// SystemVersioned is an attribute attached to MariaDB tables indicates they are\n\t// system versioned. See: https://mariadb.com/kb/en/system-versioned-tables\n\tSystemVersioned struct {\n\t\tschema.Attr\n\t}\n\n\t// OnUpdate attribute for columns with \"ON UPDATE CURRENT_TIMESTAMP\" as a default.\n\tOnUpdate struct {\n\t\tschema.Attr\n\t\tA string\n\t}\n\n\t// SubPart attribute defines an option index prefix length for columns.\n\tSubPart struct {\n\t\tschema.Attr\n\t\tLen int\n\t}\n\n\t// Enforced attribute defines the ENFORCED flag for CHECK constraint.\n\tEnforced struct {\n\t\tschema.Attr\n\t\tV bool // V indicates if the CHECK is enforced or not.\n\t}\n\n\t// The DisplayWidth represents a display width of an integer type.\n\tDisplayWidth struct {\n\t\tschema.Attr\n\t\tN int\n\t}\n\n\t// The ZeroFill represents the ZEROFILL attribute which is\n\t// deprecated for MySQL version >= 8.0.17.\n\tZeroFill struct {\n\t\tschema.Attr\n\t\tA string\n\t}\n\n\t// IndexType represents an index type.\n\tIndexType struct {\n\t\tschema.Attr\n\t\tT string // BTREE, HASH, FULLTEXT, SPATIAL, RTREE\n\t}\n\n\t// IndexParser defines the parser plugin used\n\t// by a FULLTEXT index.\n\tIndexParser struct {\n\t\tschema.Attr\n\t\tP string // Name of the parser plugin. e.g., ngram or mecab.\n\t}\n\n\t// BitType represents the type bit.\n\tBitType struct {\n\t\tschema.Type\n\t\tT    string\n\t\tSize int\n\t}\n\n\t// SetType represents a set type.\n\tSetType struct {\n\t\tschema.Type\n\t\tValues []string\n\t}\n\n\t// NetworkType stores an IPv4 or IPv6 address.\n\tNetworkType struct {\n\t\tschema.Type\n\t\tT string\n\t}\n\n\t// putShow is an intermediate table attribute used\n\t// on inspection to indicate if the 'SHOW TABLE' is\n\t// required and for what.\n\tshowTable struct {\n\t\tschema.Attr\n\t\t// AUTO_INCREMENT value due to missing value in information_schema.\n\t\tauto *AutoIncrement\n\t\t// FULLTEXT indexes that might have custom parser.\n\t\tidxs []*schema.Index\n\t}\n)\n\n// NewAutoIncrement returns an \"auto increment\" attribute.\nfunc NewAutoIncrement(v uint64) *AutoIncrement {\n\treturn &AutoIncrement{V: max(0, int64(v))} // Keep BC with old ent versions.\n}\n\n// addIndex adds an index to the list of indexes\n// that needs further processing.\nfunc (s *showTable) addFullText(idx *schema.Index) {\n\ts.idxs = append(s.idxs, idx)\n}\n\n// setAutoInc extracts the updated AUTO_INCREMENT from CREATE TABLE.\nfunc (s *showTable) setAutoInc(t *schema.Table, c *CreateStmt) error {\n\tif s.auto == nil {\n\t\treturn nil\n\t}\n\tif sqlx.Has(t.Attrs, &AutoIncrement{}) {\n\t\treturn fmt.Errorf(\"unexpected AUTO_INCREMENT attributes for table: %q\", t.Name)\n\t}\n\tmatches := reAutoinc.FindStringSubmatch(c.S)\n\tif len(matches) != 2 {\n\t\treturn nil\n\t}\n\tv, err := strconv.ParseInt(matches[1], 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\ts.auto.V = v\n\tt.Attrs = append(t.Attrs, s.auto)\n\treturn nil\n}\n\n// reIndexParser matches the parser name from the index definition.\nvar reIndexParser = regexp.MustCompile(\"/\\\\*!50100 WITH PARSER `([^`]+)` \\\\*/\")\n\n// setIndexParser updates the FULLTEXT parser from CREATE TABLE statement.\nfunc (s *showTable) setIndexParser(c *CreateStmt) {\n\tb := (&sqlx.Builder{QuoteOpening: '`', QuoteClosing: '`'}).P(\"FULLTEXT KEY\")\n\tfor _, idx := range s.idxs {\n\t\tbi := b.Clone().Ident(idx.Name).Wrap(func(b *sqlx.Builder) {\n\t\t\tb.MapComma(idx.Parts, func(i int, b *sqlx.Builder) {\n\t\t\t\t// We expect column names only, as functional\n\t\t\t\t// fulltext indexes are not supported by MySQL.\n\t\t\t\tif idx.Parts[i].C != nil {\n\t\t\t\t\tb.Ident(idx.Parts[i].C.Name)\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t\ti := strings.Index(c.S, bi.String())\n\t\tif i == -1 || i+bi.Len() >= len(c.S) {\n\t\t\tcontinue\n\t\t}\n\t\ti += bi.Len()\n\t\tj := strings.Index(c.S[i:], \"\\n\")\n\t\tif j == -1 {\n\t\t\tcontinue\n\t\t}\n\t\t// The rest of the line holds index, algorithm and lock options.\n\t\tif matches := reIndexParser.FindStringSubmatch(c.S[i : i+j]); len(matches) == 2 {\n\t\t\tidx.AddAttrs(&IndexParser{P: matches[1]})\n\t\t}\n\t}\n}\n\nfunc putShow(t *schema.Table) *showTable {\n\tfor i := range t.Attrs {\n\t\tif s, ok := t.Attrs[i].(*showTable); ok {\n\t\t\treturn s\n\t\t}\n\t}\n\ts := &showTable{}\n\tt.Attrs = append(t.Attrs, s)\n\treturn s\n}\n\nfunc popShow(t *schema.Table) (*showTable, bool) {\n\tfor i := range t.Attrs {\n\t\tif s, ok := t.Attrs[i].(*showTable); ok {\n\t\t\tt.Attrs = append(t.Attrs[:i], t.Attrs[i+1:]...)\n\t\t\treturn s, true\n\t\t}\n\t}\n\treturn nil, false\n}\n"
  },
  {
    "path": "sql/mysql/inspect_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysql\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/internal/sqltest\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\n// Single table queries used by the different tests.\nvar (\n\tqueryFKs              = sqltest.Escape(fmt.Sprintf(fksQuery, \"?\"))\n\tqueryTable            = sqltest.Escape(fmt.Sprintf(tablesQuery, \"?\"))\n\tqueryColumns          = sqltest.Escape(fmt.Sprintf(columnsExprQuery, \"?\"))\n\tqueryColumnsNoExpr    = sqltest.Escape(fmt.Sprintf(columnsQuery, \"?\"))\n\tqueryIndexes          = sqltest.Escape(fmt.Sprintf(indexesQuery, \"?\"))\n\tqueryIndexesNoComment = sqltest.Escape(fmt.Sprintf(indexesNoCommentQuery, \"?\"))\n\tqueryIndexesExpr      = sqltest.Escape(fmt.Sprintf(indexesExprQuery, \"?\"))\n\tqueryMyChecks         = sqltest.Escape(fmt.Sprintf(myChecksQuery, \"?\"))\n\tqueryMarChecks        = sqltest.Escape(fmt.Sprintf(marChecksQuery, \"?\"))\n)\n\nfunc TestDriver_InspectTable(t *testing.T) {\n\ttests := []struct {\n\t\tname    string\n\t\tversion string\n\t\tbefore  func(mock)\n\t\texpect  func(*require.Assertions, *schema.Table, error)\n\t}{\n\t\t{\n\t\t\tname: \"table collation\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.ExpectQuery(queryTable).\n\t\t\t\t\tWithArgs(\"public\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+--------------+--------------+--------------------+--------------------+----------------+---------------+-------------------+------------------+------------------+------------------+ \n| TABLE_SCHEMA | TABLE_NAME   | CHARACTER_SET_NAME | TABLE_COLLATION    | AUTO_INCREMENT | TABLE_COMMENT | CREATE_OPTIONS    |      ENGINE      |  DEFAULT_ENGINE  |  TABLE_TYPE      | \n+--------------+--------------+--------------------+--------------------+----------------+---------------+-------------------+------------------+------------------+------------------+ \n| public       | users        | utf8mb4            | utf8mb4_0900_ai_ci | nil            | Comment       | COMPRESSION=\"ZLIB\"|       InnoDB     |       1          |                  | \n+--------------+--------------+--------------------+--------------------+----------------+---------------+-------------------+------------------+------------------+------------------+ \n`))\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+--------------------+--------------------+----------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+---------------------------+\n| table_name         | column_name        | column_type          | column_comment       | is_nullable | column_key | column_default | extra          | character_set_name | collation_name | generation_expression     |\n+--------------------+--------------------+----------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+---------------------------+\n| users              | id                 | bigint(20)           |                      | NO          | PRI        | NULL           | auto_increment | NULL               | NULL           | NULL                      |\n+--------------------+--------------------+----------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+---------------------------+\n`))\n\t\t\t\tm.ExpectQuery(queryIndexesExpr).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+--------------------+--------------+-------------+------------+--------------+--------------+----------+--------------+------------+------------------+\n| TABLE_NAME         | INDEX_NAME   | COLUMN_NAME | NON_UNIQUE | SEQ_IN_INDEX | INDEX_TYPE   | DESC     | COMMENT      | SUB_PART   | EXPRESSION       |\n+--------------------+--------------+-------------+------------+--------------+--------------+----------+--------------+------------+------------------+\n| users              | PRIMARY      | id          |          0 |            1 | BTREE        | 0        |              |       NULL |      NULL        |\n+--------------------+--------------+-------------+------------+--------------+--------------+----------+--------------+------------+------------------+\n`))\n\t\t\t\tm.noFKs()\n\t\t\t\tm.ExpectQuery(sqltest.Escape(\"SHOW CREATE TABLE `public`.`users`\")).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+-------+---------------------------------------------------------------------------------------------------------------------------------------------+\n| Table | Create Table                                                                                                                                |\n+-------+---------------------------------------------------------------------------------------------------------------------------------------------+\n| users | CREATE TABLE users (id bigint NOT NULL AUTO_INCREMENT) ENGINE=InnoDB AUTO_INCREMENT=55834574848 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |\n+-------+---------------------------------------------------------------------------------------------------------------------------------------------+\n`))\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]schema.Attr{\n\t\t\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t\t&schema.Collation{V: \"utf8mb4_0900_ai_ci\"},\n\t\t\t\t\t&schema.Comment{Text: \"Comment\"},\n\t\t\t\t\t&CreateOptions{V: `COMPRESSION=\"ZLIB\"`},\n\t\t\t\t\t&Engine{V: \"InnoDB\", Default: true},\n\t\t\t\t\t&CreateStmt{S: \"CREATE TABLE users (id bigint NOT NULL AUTO_INCREMENT) ENGINE=InnoDB AUTO_INCREMENT=55834574848 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\"},\n\t\t\t\t\t&AutoIncrement{V: 55834574848},\n\t\t\t\t}, t.Attrs)\n\t\t\t\trequire.Len(t.PrimaryKey.Parts, 1)\n\t\t\t\trequire.True(t.PrimaryKey.Parts[0].C == t.Columns[0])\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint(20)\", Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&AutoIncrement{V: 55834574848}}, Indexes: []*schema.Index{t.PrimaryKey}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"int types\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.ExpectQuery(queryTable).\n\t\t\t\t\tWithArgs(\"public\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+--------------+--------------+--------------------+--------------------+----------------+---------------+--------------------+------------------+------------------+------------------+ \n| TABLE_SCHEMA | TABLE_NAME   | CHARACTER_SET_NAME | TABLE_COLLATION    | AUTO_INCREMENT | TABLE_COMMENT | CREATE_OPTIONS     |      ENGINE      |  DEFAULT_ENGINE  |  TABLE_TYPE      | \n+--------------+--------------+--------------------+--------------------+----------------+---------------+--------------------+------------------+------------------+------------------+ \n| public       | users        | utf8mb4            | utf8mb4_0900_ai_ci | nil            | Comment       | COMPRESSION=\"ZLIB\" |       InnoDB     |       1          |                  | \n+--------------+--------------+--------------------+--------------------+----------------+---------------+--------------------+------------------+------------------+------------------+ \n`))\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+--------------------+------------------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+---------------------------+\n| table_name | column_name        | column_type                  | column_comment       | is_nullable | column_key | column_default | extra          | character_set_name | collation_name | generation_expression     |\n+----------- +--------------------+------------------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+---------------------------+\n| users      | id                 | bigint(20)                   |                      | NO          | PRI        | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v57_tiny           | tinyint(1)                   |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v57_tiny_unsigned  | tinyint(4) unsigned          |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v57_small          | smallint(6)                  |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v57_small_unsigned | smallint(6) unsigned         |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v57_int            | bigint(11)                   |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v57_int_unsigned   | bigint(11) unsigned          |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v8_tiny            | tinyint                      |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v8_tiny_unsigned   | tinyint unsigned             |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v8_small           | smallint                     |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v8_small_unsigned  | smallint unsigned            |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v8_big             | bigint                       |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v8_big_unsigned    | bigint unsigned              | comment              | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      | v8_big_zerofill    | bigint(20) unsigned zerofill | comment              | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n+------------+--------------------+------------------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint(20)\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t{Name: \"v57_tiny\", Type: &schema.ColumnType{Raw: \"tinyint(1)\", Type: &schema.BoolType{T: \"bool\"}}},\n\t\t\t\t\t{Name: \"v57_tiny_unsigned\", Type: &schema.ColumnType{Raw: \"tinyint(4) unsigned\", Type: &schema.IntegerType{T: \"tinyint\", Unsigned: true}}},\n\t\t\t\t\t{Name: \"v57_small\", Type: &schema.ColumnType{Raw: \"smallint(6)\", Type: &schema.IntegerType{T: \"smallint\"}}},\n\t\t\t\t\t{Name: \"v57_small_unsigned\", Type: &schema.ColumnType{Raw: \"smallint(6) unsigned\", Type: &schema.IntegerType{T: \"smallint\", Unsigned: true}}},\n\t\t\t\t\t{Name: \"v57_int\", Type: &schema.ColumnType{Raw: \"bigint(11)\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t{Name: \"v57_int_unsigned\", Type: &schema.ColumnType{Raw: \"bigint(11) unsigned\", Type: &schema.IntegerType{T: \"bigint\", Unsigned: true}}},\n\t\t\t\t\t{Name: \"v8_tiny\", Type: &schema.ColumnType{Raw: \"tinyint\", Type: &schema.IntegerType{T: \"tinyint\"}}},\n\t\t\t\t\t{Name: \"v8_tiny_unsigned\", Type: &schema.ColumnType{Raw: \"tinyint unsigned\", Type: &schema.IntegerType{T: \"tinyint\", Unsigned: true}}},\n\t\t\t\t\t{Name: \"v8_small\", Type: &schema.ColumnType{Raw: \"smallint\", Type: &schema.IntegerType{T: \"smallint\"}}},\n\t\t\t\t\t{Name: \"v8_small_unsigned\", Type: &schema.ColumnType{Raw: \"smallint unsigned\", Type: &schema.IntegerType{T: \"smallint\", Unsigned: true}}},\n\t\t\t\t\t{Name: \"v8_big\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t{Name: \"v8_big_unsigned\", Type: &schema.ColumnType{Raw: \"bigint unsigned\", Type: &schema.IntegerType{T: \"bigint\", Unsigned: true}}, Attrs: []schema.Attr{&schema.Comment{Text: \"comment\"}}},\n\t\t\t\t\t{Name: \"v8_big_zerofill\", Type: &schema.ColumnType{Raw: \"bigint(20) unsigned zerofill\", Type: &schema.IntegerType{T: \"bigint\", Unsigned: true, Attrs: []schema.Attr{&DisplayWidth{N: 20}, &ZeroFill{A: \"zerofill\"}}}}, Attrs: []schema.Attr{&schema.Comment{Text: \"comment\"}}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"maria/types\",\n\t\t\tversion: \"10.7.1-MariaDB\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+----------------+-------------------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+---------------------------+\n| table_name |  column_name   | column_type                   | column_comment       | is_nullable | column_key | column_default | extra          | character_set_name | collation_name | generation_expression     |\n+------------+----------------+-------------------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+---------------------------+\n| users      |  id            | bigint(20)                    |                      | NO          | PRI        | NULL           |                | NULL               | NULL           | NULL                      |\n| users      |  tiny_int      | tinyint(1)                    |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      |  longtext      | longtext                      |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      |  jsonc         | longtext                      |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      |  dt0           | datetime /* mariadb-5.3 */    |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      |  dt1           | datetime(6) /* mariadb-5.3 */ |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      |  dt2           | time(1) /* mariadb-5.3 */     |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      |  inet4         | inet4                         |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n| users      |  inet6         | inet6                         |                      | NO          |            | NULL           |                | NULL               | NULL           | NULL                      |\n+------------+----------------+-------------------------------+----------------------+-------------+------------+----------------+----------------+--------------------+----------------+---------------------------+\n`))\n\t\t\t\tm.ExpectQuery(queryIndexes).\n\t\t\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_name\", \"index_name\", \"column_name\", \"non_unique\", \"key_part\", \"expression\"}))\n\t\t\t\tm.noFKs()\n\t\t\t\tm.ExpectQuery(queryMarChecks).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+--------+------------------+-------------------------------------------+------------+\n| table  | CONSTRAINT_NAME  | CHECK_CLAUSE                              |  ENFORCED  |\n+--------+------------------+-------------------------------------------+------------+\n| users  | jsonc            | json_valid(` + \"`jsonc`\" + `)             |  YES       |\n| users  | users_chk_1      | longtext <> '\\'\\'\"\"'                      |  YES       |\n+--------+------------------+-------------------------------------------+------------+\n`))\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint(20)\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t{Name: \"tiny_int\", Type: &schema.ColumnType{Raw: \"tinyint(1)\", Type: &schema.BoolType{T: \"bool\"}}},\n\t\t\t\t\t{Name: \"longtext\", Type: &schema.ColumnType{Raw: \"longtext\", Type: &schema.StringType{T: \"longtext\"}}},\n\t\t\t\t\t{Name: \"jsonc\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}},\n\t\t\t\t\t{Name: \"dt0\", Type: &schema.ColumnType{Raw: \"datetime /* mariadb-5.3 */\", Type: &schema.TimeType{T: \"datetime\"}}},\n\t\t\t\t\t{Name: \"dt1\", Type: &schema.ColumnType{Raw: \"datetime(6) /* mariadb-5.3 */\", Type: &schema.TimeType{T: \"datetime\", Precision: sqlx.P(6)}}},\n\t\t\t\t\t{Name: \"dt2\", Type: &schema.ColumnType{Raw: \"time(1) /* mariadb-5.3 */\", Type: &schema.TimeType{T: \"time\", Precision: sqlx.P(1)}}},\n\t\t\t\t\t{Name: \"inet4\", Type: &schema.ColumnType{Raw: \"inet4\", Type: &NetworkType{T: \"inet4\"}}},\n\t\t\t\t\t{Name: \"inet6\", Type: &schema.ColumnType{Raw: \"inet6\", Type: &NetworkType{T: \"inet6\"}}},\n\t\t\t\t}, t.Columns)\n\t\t\t\trequire.EqualValues([]schema.Attr{\n\t\t\t\t\t&schema.Check{Name: \"users_chk_1\", Expr: `longtext <> '\\'\\'\"\"'`},\n\t\t\t\t}, t.Attrs)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"decimal types\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+--------------+------------------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| table_name |  column_name |      column_type       | column_comment | is_nullable | column_key | column_default | extra | character_set_name | collation_name | generation_expression     |\n+------------+--------------+------------------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| users      |  d1          | decimal(10,2)          |                | NO          |            | 10.20          |       | NULL               | NULL           | NULL                      |\n| users      |  d2          | decimal(10,0)          |                | NO          |            | 10             |       | NULL               | NULL           | NULL                      |\n| users      |  d3          | decimal(10,2) unsigned |                | NO          |            | 10.20          |       | NULL               | NULL           | NULL                      |\n| users      |  d4          | decimal(10,0) unsigned |                | NO          |            | 10             |       | NULL               | NULL           | NULL                      |\n+------------+-------------+-------------------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"d1\", Type: &schema.ColumnType{Raw: \"decimal(10,2)\", Type: &schema.DecimalType{T: \"decimal\", Precision: 10, Scale: 2}}, Default: &schema.Literal{V: \"10.20\"}},\n\t\t\t\t\t{Name: \"d2\", Type: &schema.ColumnType{Raw: \"decimal(10,0)\", Type: &schema.DecimalType{T: \"decimal\", Precision: 10, Scale: 0}}, Default: &schema.Literal{V: \"10\"}},\n\t\t\t\t\t{Name: \"d3\", Type: &schema.ColumnType{Raw: \"decimal(10,2) unsigned\", Type: &schema.DecimalType{T: \"decimal\", Precision: 10, Scale: 2, Unsigned: true}}, Default: &schema.Literal{V: \"10.20\"}},\n\t\t\t\t\t{Name: \"d4\", Type: &schema.ColumnType{Raw: \"decimal(10,0) unsigned\", Type: &schema.DecimalType{T: \"decimal\", Precision: 10, Scale: 0, Unsigned: true}}, Default: &schema.Literal{V: \"10\"}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"float types\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+----------------------------+--------------------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| table_name |    column_name             | column_type              | column_comment | is_nullable | column_key | column_default | extra | character_set_name | collation_name | generation_expression     |\n+------------+----------------------------+--------------------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| users      |  float                     | float                    |                | NO          |            |                |       | NULL               | NULL           | NULL                      |\n| users      |  double                    | double                   |                | NO          |            |                |       | NULL               | NULL           | NULL                      |\n| users      |  float_unsigned            | float unsigned           |                | NO          |            |                |       | NULL               | NULL           | NULL                      |\n| users      |  double_unsigned           | double unsigned          |                | NO          |            |                |       | NULL               | NULL           | NULL                      |\n| users      |  float_unsigned_p          | float(10) unsigned       |                | NO          |            |                |       | NULL               | NULL           | NULL                      |\n| users      |  doubled_zerofill_unsigned | double unsigned zerofill |                | NO          |            |                |       | NULL               | NULL           | NULL                      |\n+------------+-------------------+--------------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"float\", Type: &schema.ColumnType{Raw: \"float\", Type: &schema.FloatType{T: \"float\"}}},\n\t\t\t\t\t{Name: \"double\", Type: &schema.ColumnType{Raw: \"double\", Type: &schema.FloatType{T: \"double\"}}},\n\t\t\t\t\t{Name: \"float_unsigned\", Type: &schema.ColumnType{Raw: \"float unsigned\", Type: &schema.FloatType{T: \"float\", Unsigned: true}}},\n\t\t\t\t\t{Name: \"double_unsigned\", Type: &schema.ColumnType{Raw: \"double unsigned\", Type: &schema.FloatType{T: \"double\", Unsigned: true}}},\n\t\t\t\t\t{Name: \"float_unsigned_p\", Type: &schema.ColumnType{Raw: \"float(10) unsigned\", Type: &schema.FloatType{T: \"float\", Precision: 10, Unsigned: true}}},\n\t\t\t\t\t{Name: \"doubled_zerofill_unsigned\", Type: &schema.ColumnType{Raw: \"double unsigned zerofill\", Type: &schema.FloatType{T: \"double\", Unsigned: true}}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"binary types\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+--------------+---------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| table_name |  column_name | column_type   | column_comment | is_nullable | column_key | column_default | extra | character_set_name | collation_name | generation_expression     |\n+------------+--------------+---------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| users      |  c1          | binary(20)    |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      |  c2          | varbinary(30) |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      |  c3          | tinyblob      |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      |  c4          | mediumblob    |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      |  c5          | blob          |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      |  c6          | longblob      |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n+------------+--------------+---------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\tp := func(i int) *int { return &i }\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"binary(20)\", Type: &schema.BinaryType{T: \"binary\", Size: p(20)}}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"varbinary(30)\", Type: &schema.BinaryType{T: \"varbinary\", Size: p(30)}}},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"tinyblob\", Type: &schema.BinaryType{T: \"tinyblob\"}}},\n\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Raw: \"mediumblob\", Type: &schema.BinaryType{T: \"mediumblob\"}}},\n\t\t\t\t\t{Name: \"c5\", Type: &schema.ColumnType{Raw: \"blob\", Type: &schema.BinaryType{T: \"blob\"}}},\n\t\t\t\t\t{Name: \"c6\", Type: &schema.ColumnType{Raw: \"longblob\", Type: &schema.BinaryType{T: \"longblob\"}}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"bit type\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+------------+-------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| TABLE_NAME |COLUMN_NAME | COLUMN_TYPE | COLUMN_COMMENT | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA | CHARACTER_SET_NAME | COLLATION_NAME | GENERATION_EXPRESSION     |\n+------------+------------+-------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| users      |c1          | bit        |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                       |\n| users      |c2          | bit(1)     |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                       |\n| users      |c3          | bit(2)     |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                       |\n+------------+------------+-------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"bit\", Type: &BitType{T: \"bit\"}}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"bit(1)\", Type: &BitType{T: \"bit\", Size: 1}}},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"bit(2)\", Type: &BitType{T: \"bit\", Size: 2}}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"string types\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+-------------+---------------+----------------+-------------+------------+--------------------------------------------+-------------------+--------------------+----------------+---------------------------+\n| table_name | column_name | column_type   | column_comment | is_nullable | column_key | column_default                             | extra             | character_set_name | collation_name | generation_expression     |\n+------------+-------------+---------------+----------------+-------------+------------+--------------------------------------------+-------------------+--------------------+----------------+---------------------------+\n| users      | c1          | char(20)      |                | NO          |            | char                                       |                   | NULL               | NULL           | NULL                      |\n| users      | c2          | varchar(30)   |                | NO          |            | NULL                                       |                   | NULL               | NULL           | NULL                      |\n| users      | c3          | tinytext      |                | NO          |            | NULL                                       |                   | NULL               | NULL           | NULL                      |\n| users      | c4          | mediumtext    |                | NO          |            | NULL                                       |                   | NULL               | NULL           | NULL                      |\n| users      | c5          | text          |                | NO          |            | NULL                                       |                   | NULL               | NULL           | NULL                      |\n| users      | c6          | longtext      |                | NO          |            | NULL                                       |                   | NULL               | NULL           | NULL                      |\n| users      | c7          | varchar(20)   |                | NO          |            | concat(_latin1\\'Hello \\',` + \"`name`\" + `) | DEFAULT_GENERATED | NULL               | NULL           | NULL                      |\n+------------+-------------+---------------+----------------+-------------+------------+--------------------------------------------+-------------------+--------------------+----------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"char(20)\", Type: &schema.StringType{T: \"char\", Size: 20}}, Default: &schema.Literal{V: `\"char\"`}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"varchar(30)\", Type: &schema.StringType{T: \"varchar\", Size: 30}}},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"tinytext\", Type: &schema.StringType{T: \"tinytext\"}}},\n\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Raw: \"mediumtext\", Type: &schema.StringType{T: \"mediumtext\"}}},\n\t\t\t\t\t{Name: \"c5\", Type: &schema.ColumnType{Raw: \"text\", Type: &schema.StringType{T: \"text\"}}},\n\t\t\t\t\t{Name: \"c6\", Type: &schema.ColumnType{Raw: \"longtext\", Type: &schema.StringType{T: \"longtext\"}}},\n\t\t\t\t\t{Name: \"c7\", Type: &schema.ColumnType{Raw: \"varchar(20)\", Type: &schema.StringType{T: \"varchar\", Size: 20}}, Default: &schema.RawExpr{X: \"(concat(_latin1'Hello ',`name`))\"}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"enum type\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+-------------+---------------+----------------+-------------+------------+----------------+-------+--------------------+-------------------+---------------------------+\n| table_name | column_name | column_type   | column_comment | is_nullable | column_key | column_default | extra | character_set_name | collation_name    | generation_expression     |\n+------------+-------------+---------------+----------------+-------------+------------+----------------+-------+--------------------+-------------------+---------------------------+\n| users      | c1          | enum('a','b') |                | NO          |            | NULL           |       | latin1             | latin1_swedish_ci | NULL                      |\n| users      | c2          | enum('c','d') |                | NO          |            | d              |       | latin1             | latin1_swedish_ci | NULL                      |\n+------------+-------------+---------------+----------------+-------------+------------+----------------+-------+--------------------+-------------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"enum('a','b')\", Type: &schema.EnumType{T: \"enum\", Values: []string{\"a\", \"b\"}}}, Attrs: []schema.Attr{&schema.Charset{V: \"latin1\"}, &schema.Collation{V: \"latin1_swedish_ci\"}}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"enum('c','d')\", Type: &schema.EnumType{T: \"enum\", Values: []string{\"c\", \"d\"}}}, Default: &schema.Literal{V: `\"d\"`}, Attrs: []schema.Attr{&schema.Charset{V: \"latin1\"}, &schema.Collation{V: \"latin1_swedish_ci\"}}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"time type\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+-------------+--------------+-------------------+-------------+------------+----------------------+--------------------------------+--------------------+----------------+---------------------------+\n| table_name | column_name | column_type  | column_comment    | is_nullable | column_key | column_default       | extra                          | character_set_name | collation_name | generation_expression     |\n+------------+-------------+--------------+-------------------+-------------+------------+----------------------+--------------------------------+--------------------+----------------+---------------------------+\n| users      | c1          | date         |                   | NO          |            | NULL                 |                                | NULL               | NULL           | NULL                      |\n| users      | c2          | datetime     |                   | NO          |            | NULL                 |                                | NULL               | NULL           | NULL                      |\n| users      | c3          | time         |                   | NO          |            | NULL                 |                                | NULL               | NULL           | NULL                      |\n| users      | c4          | timestamp    |                   | NO          |            | CURRENT_TIMESTAMP    | on update CURRENT_TIMESTAMP    | NULL               | NULL           | NULL                      |\n| users      | c5          | year(4)      |                   | NO          |            | NULL                 |                                | NULL               | NULL           | NULL                      |\n| users      | c6          | year         |                   | NO          |            | NULL                 |                                | NULL               | NULL           | NULL                      |\n| users      | c7          | timestamp(6) |                   | NO          |            | CURRENT_TIMESTAMP(6) | on update CURRENT_TIMESTAMP(6) | NULL               | NULL           | NULL                      |\n+------------+--------------+-------------------+-------------+------------+----------------------+--------------------------------+--------------------+-------------+----------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\tp := func(i int) *int { return &i }\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"date\", Type: &schema.TimeType{T: \"date\"}}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"datetime\", Type: &schema.TimeType{T: \"datetime\"}}},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"time\", Type: &schema.TimeType{T: \"time\"}}},\n\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Raw: \"timestamp\", Type: &schema.TimeType{T: \"timestamp\"}}, Default: &schema.RawExpr{X: \"CURRENT_TIMESTAMP\"}, Attrs: []schema.Attr{&OnUpdate{A: \"CURRENT_TIMESTAMP\"}}},\n\t\t\t\t\t{Name: \"c5\", Type: &schema.ColumnType{Raw: \"year(4)\", Type: &schema.TimeType{T: \"year\", Precision: p(4)}}},\n\t\t\t\t\t{Name: \"c6\", Type: &schema.ColumnType{Raw: \"year\", Type: &schema.TimeType{T: \"year\"}}},\n\t\t\t\t\t{Name: \"c7\", Type: &schema.ColumnType{Raw: \"timestamp(6)\", Type: &schema.TimeType{T: \"timestamp\", Precision: p(6)}}, Default: &schema.RawExpr{X: \"CURRENT_TIMESTAMP(6)\"}, Attrs: []schema.Attr{&OnUpdate{A: \"CURRENT_TIMESTAMP(6)\"}}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"json type\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+------------+-------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| TABLE_NAME |COLUMN_NAME | COLUMN_TYPE | COLUMN_COMMENT | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA | CHARACTER_SET_NAME | COLLATION_NAME | GENERATION_EXPRESSION     |\n+------------+------------+-------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| users      |c1          | json        |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n+------------+------------+-------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"spatial type\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+-------------+--------------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| table_name | column_name | column_type        | column_comment | is_nullable | column_key | column_default | extra | character_set_name | collation_name | GENERATION_EXPRESSION     |\n+------------+-------------+--------------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n| users      | c1          | point              |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      | c2          | multipoint         |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      | c3          | linestring         |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      | c4          | multilinestring    |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      | c5          | polygon            |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      | c6          | multipolygon       |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      | c7          | geometry           |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      | c8          | geometrycollection |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n| users      | c9          | geomcollection     |                | NO          |            | NULL           |       | NULL               | NULL           | NULL                      |\n+------------+-------------+--------------------+----------------+-------------+------------+----------------+-------+--------------------+----------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"point\", Type: &schema.SpatialType{T: \"point\"}}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"multipoint\", Type: &schema.SpatialType{T: \"multipoint\"}}},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"linestring\", Type: &schema.SpatialType{T: \"linestring\"}}},\n\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Raw: \"multilinestring\", Type: &schema.SpatialType{T: \"multilinestring\"}}},\n\t\t\t\t\t{Name: \"c5\", Type: &schema.ColumnType{Raw: \"polygon\", Type: &schema.SpatialType{T: \"polygon\"}}},\n\t\t\t\t\t{Name: \"c6\", Type: &schema.ColumnType{Raw: \"multipolygon\", Type: &schema.SpatialType{T: \"multipolygon\"}}},\n\t\t\t\t\t{Name: \"c7\", Type: &schema.ColumnType{Raw: \"geometry\", Type: &schema.SpatialType{T: \"geometry\"}}},\n\t\t\t\t\t{Name: \"c8\", Type: &schema.ColumnType{Raw: \"geometrycollection\", Type: &schema.SpatialType{T: \"geometrycollection\"}}},\n\t\t\t\t\t{Name: \"c9\", Type: &schema.ColumnType{Raw: \"geomcollection\", Type: &schema.SpatialType{T: \"geomcollection\"}}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"generated columns\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+-------------+-------------+----------------+-------------+------------+----------------+-------------------+--------------------+----------------+--------------------------------------+\n| TABLE_NAME | COLUMN_NAME | COLUMN_TYPE | COLUMN_COMMENT | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA             | CHARACTER_SET_NAME | COLLATION_NAME | GENERATION_EXPRESSION                |\n+------------+-------------+-------------+----------------+-------------+------------+----------------+-------------------+--------------------+----------------+--------------------------------------+\n| users      | c1          | int         |                | NO          |            | NULL           |                   | NULL               | NULL           |                                      |\n| users      | c2          | int         |                | NO          |            | NULL           | VIRTUAL GENERATED | NULL               | NULL           | ` + \"(`c1` * `c1`)\" + `              |\n| users      | c3          | int         |                | NO          |            | NULL           | STORED GENERATED  | NULL               | NULL           | ` + \"(`c1` + `c2`)\" + `              |\n| users      | c4          | varchar(20) |                | NO          |            | NULL           | STORED GENERATED  | NULL               | NULL           | concat(_latin1\\'\\\\\\'\\',_latin1\\'\"\\') |\n+------------+-------------+-------------+----------------+-------------+------------+----------------+-------------------+--------------------+----------------+--------------------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}, Attrs: []schema.Attr{&schema.GeneratedExpr{Expr: \"(`c1` * `c1`)\", Type: \"VIRTUAL\"}}},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}, Attrs: []schema.Attr{&schema.GeneratedExpr{Expr: \"(`c1` + `c2`)\", Type: \"STORED\"}}},\n\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Raw: \"varchar(20)\", Type: &schema.StringType{T: \"varchar\", Size: 20}}, Attrs: []schema.Attr{&schema.GeneratedExpr{Expr: \"concat(_latin1'\\\\'',_latin1'\\\"')\", Type: \"STORED\"}}},\n\t\t\t\t}, t.Columns)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"indexes\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n| TABLE_NAME | COLUMN_NAME | COLUMN_TYPE  | COLUMN_COMMENT | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA          | CHARACTER_SET_NAME | COLLATION_NAME     | GENERATION_EXPRESSION     |\n+------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n| users      | id          | int          |                | NO          | PRI        | NULL           |                | NULL               | NULL               | NULL                      |\n| users      | nickname    | varchar(255) |                | NO          | UNI        | NULL           |                | utf8mb4            | utf8mb4_0900_ai_ci | NULL                      |\n| users      | oid         | int          |                | NO          | MUL        | NULL           |                | NULL               | NULL               | NULL                      |\n| users      | uid         | int          |                | NO          | MUL        | NULL           |                | NULL               | NULL               | NULL                      |\n+------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n`))\n\t\t\t\tm.ExpectQuery(queryIndexesExpr).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+--------------+--------------+-------------+------------+--------------+--------------+---------+--------------+------------+------------------+\n| TABLE_NAME   | INDEX_NAME   | COLUMN_NAME | NON_UNIQUE | SEQ_IN_INDEX | INDEX_TYPE   | DESC    | COMMENT      | SUB_PART   | EXPRESSION       |\n+--------------+--------------+-------------+------------+--------------+--------------+---------+--------------+------------+------------------+\n| users        | nickname     | nickname    |          0 |            1 | BTREE        | nil     |              |        255 |      NULL        |\n| users        | lower_nick   | NULL        |          1 |            1 | HASH         | 0       |              |       NULL | lower(nickname)  |\n| users        | non_unique   | oid         |          1 |            1 | BTREE        | 0       |              |       NULL |      NULL        |\n| users        | non_unique   | uid         |          1 |            2 | BTREE        | 0       |              |       NULL |      NULL        |\n| users        | PRIMARY      | id          |          0 |            1 | BTREE        | 0       |              |       NULL |      NULL        |\n| users        | unique_index | uid         |          0 |            1 | BTREE        | 1       |              |       NULL |      NULL        |\n| users        | unique_index | oid         |          0 |            2 | BTREE        | 1       |              |       NULL |      NULL        |\n+--------------+--------------+-------------+------------+--------------+--------------+---------+--------------+------------+------------------+\n`))\n\t\t\t\tm.noFKs()\n\t\t\t\tm.ExpectQuery(sqltest.Escape(\"SHOW CREATE TABLE `public`.`users`\")).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+-------+---------------------------------------------------------------------------------------------------------------------------------------------+\n| Table | Create Table                                                                                                                                |\n+-------+---------------------------------------------------------------------------------------------------------------------------------------------+\n+-------+---------------------------------------------------------------------------------------------------------------------------------------------+\n| users | CREATE TABLE users (id bigint NOT NULL AUTO_INCREMENT) ENGINE=InnoDB AUTO_INCREMENT=55834574848 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |\n+-------+---------------------------------------------------------------------------------------------------------------------------------------------+\n`))\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\tindexes := []*schema.Index{\n\t\t\t\t\t{Name: \"nickname\", Unique: true, Table: t, Attrs: []schema.Attr{&IndexType{T: \"BTREE\"}}}, // Implicitly created by the UNIQUE clause.\n\t\t\t\t\t{Name: \"lower_nick\", Table: t, Attrs: []schema.Attr{&IndexType{T: \"HASH\"}}},\n\t\t\t\t\t{Name: \"non_unique\", Table: t, Attrs: []schema.Attr{&IndexType{T: \"BTREE\"}}},\n\t\t\t\t\t{Name: \"unique_index\", Unique: true, Table: t, Attrs: []schema.Attr{&IndexType{T: \"BTREE\"}}},\n\t\t\t\t}\n\t\t\t\tcolumns := []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}, Indexes: []*schema.Index{t.PrimaryKey}},\n\t\t\t\t\t{Name: \"nickname\", Type: &schema.ColumnType{Raw: \"varchar(255)\", Type: &schema.StringType{T: \"varchar\", Size: 255}}, Indexes: indexes[0:1], Attrs: []schema.Attr{&schema.Charset{V: \"utf8mb4\"}, &schema.Collation{V: \"utf8mb4_0900_ai_ci\"}}},\n\t\t\t\t\t{Name: \"oid\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}, Indexes: indexes[2:]},\n\t\t\t\t\t{Name: \"uid\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}, Indexes: indexes[2:]},\n\t\t\t\t}\n\t\t\t\t// nickname\n\t\t\t\tindexes[0].Parts = []*schema.IndexPart{\n\t\t\t\t\t{SeqNo: 1, C: columns[1], Attrs: []schema.Attr{&SubPart{Len: 255}}},\n\t\t\t\t}\n\t\t\t\t// lower(nickname)\n\t\t\t\tindexes[1].Parts = []*schema.IndexPart{\n\t\t\t\t\t{SeqNo: 1, X: &schema.RawExpr{X: \"lower(nickname)\"}},\n\t\t\t\t}\n\t\t\t\t// oid, uid\n\t\t\t\tindexes[2].Parts = []*schema.IndexPart{\n\t\t\t\t\t{SeqNo: 1, C: columns[2]},\n\t\t\t\t\t{SeqNo: 2, C: columns[3]},\n\t\t\t\t}\n\t\t\t\t// uid, oid\n\t\t\t\tindexes[3].Parts = []*schema.IndexPart{\n\t\t\t\t\t{SeqNo: 1, C: columns[3], Desc: true},\n\t\t\t\t\t{SeqNo: 2, C: columns[2], Desc: true},\n\t\t\t\t}\n\t\t\t\trequire.EqualValues(columns, t.Columns)\n\t\t\t\trequire.EqualValues(indexes, t.Indexes)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"indexes/not_support_comment\",\n\t\t\tversion: \"5.1.60\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumnsNoExpr).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n| TABLE_NAME | COLUMN_NAME | COLUMN_TYPE  | COLUMN_COMMENT | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA          | CHARACTER_SET_NAME | COLLATION_NAME     | GENERATION_EXPRESSION     |\n+------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n| users      | id          | int          |                | NO          | PRI        | NULL           |                | NULL               | NULL               | NULL                      |\n+------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n`))\n\t\t\t\tm.ExpectQuery(queryIndexesNoComment).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+--------------+--------------+-------------+------------+--------------+--------------+---------+--------------+------------+------------------+\n| TABLE_NAME   | INDEX_NAME   | COLUMN_NAME | NON_UNIQUE | SEQ_IN_INDEX | INDEX_TYPE   | DESC    | COMMENT      | SUB_PART   | EXPRESSION       |\n+--------------+--------------+-------------+------------+--------------+--------------+---------+--------------+------------+------------------+\n| users        | PRIMARY      | id          |          0 |            1 | BTREE        | 0       | NULL         |       NULL |      NULL        |\n+--------------+--------------+-------------+------------+--------------+--------------+---------+--------------+------------+------------------+\n`))\n\t\t\t\tm.noFKs()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, _ *schema.Table, err error) {\n\t\t\t\t// nothing to expect, ExpectQuery is enough for this test\n\t\t\t\trequire.NoError(err)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"fks\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n| TABLE_NAME | COLUMN_NAME | COLUMN_TYPE  | COLUMN_COMMENT | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA          | CHARACTER_SET_NAME | COLLATION_NAME     | GENERATION_EXPRESSION     |\n+------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n| users      | id          | int          |                | NO          | PRI        | NULL           |                | NULL               | NULL               | NULL                      |\n| users      | oid         | int          |                | NO          | MUL        | NULL           |                | NULL               | NULL               | NULL                      |\n| users      | uid         | int          |                | NO          | MUL        | NULL           |                | NULL               | NULL               | NULL                      |\n+------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.ExpectQuery(queryFKs).\n\t\t\t\t\tWithArgs(\"public\", \"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------------+------------+-------------+--------------+-----------------------+------------------------+------------------------+-------------+-------------+\n| CONSTRAINT_NAME  | TABLE_NAME | COLUMN_NAME | TABLE_SCHEMA | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME | REFERENCED_SCHEMA_NAME | UPDATE_RULE | DELETE_RULE |\n+------------------+------------+-------------+--------------+-----------------------+------------------------+------------------------+-------------+-------------+\n| multi_column     | users      | id          | public       | t1                    | gid                    | public                 | NO ACTION   | CASCADE     |\n| multi_column     | users      | oid         | public       | t1                    | xid                    | public                 | NO ACTION   | CASCADE     |\n| self_reference   | users      | uid         | public       | users                 | id                     | public                 | NO ACTION   | CASCADE     |\n+------------------+------------+-------------+--------------+-----------------------+------------------------+------------------------+ ------------+-------------+\n`))\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.Equal(\"public\", t.Schema.Name)\n\t\t\t\tfks := []*schema.ForeignKey{\n\t\t\t\t\t{Symbol: \"multi_column\", Table: t, OnUpdate: schema.NoAction, OnDelete: schema.Cascade, RefTable: &schema.Table{Name: \"t1\", Schema: t.Schema}, RefColumns: []*schema.Column{{Name: \"gid\"}, {Name: \"xid\"}}},\n\t\t\t\t\t{Symbol: \"self_reference\", Table: t, OnUpdate: schema.NoAction, OnDelete: schema.Cascade, RefTable: t},\n\t\t\t\t}\n\t\t\t\tcolumns := []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}, ForeignKeys: fks[0:1]},\n\t\t\t\t\t{Name: \"oid\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}, ForeignKeys: fks[0:1]},\n\t\t\t\t\t{Name: \"uid\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}, ForeignKeys: fks[1:2]},\n\t\t\t\t}\n\t\t\t\tfks[0].Columns = columns[:2]\n\t\t\t\tfks[1].Columns = columns[2:]\n\t\t\t\tfks[1].RefColumns = columns[:1]\n\t\t\t\trequire.EqualValues(columns, t.Columns)\n\t\t\t\trequire.EqualValues(fks, t.ForeignKeys)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"checks\",\n\t\t\tversion: \"8.0.16\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+-------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n| TABLE_NAME  | COLUMN_NAME | COLUMN_TYPE  | COLUMN_COMMENT | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA          | CHARACTER_SET_NAME | COLLATION_NAME     | GENERATION_EXPRESSION     |\n+-------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n| users       | id          | int          |                | NO          | PRI        | NULL           |                | NULL               | NULL               | NULL                      |\n| users       | c1          | int          |                | NO          | MUL        | NULL           |                | NULL               | NULL               | NULL                      |\n+-------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t\tm.ExpectQuery(queryMyChecks).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+-------------------+-------------------+-------------------------------------------+------------+\n| TABLE_NAME        | CONSTRAINT_NAME   | CHECK_CLAUSE                              |  ENFORCED  |\n+-------------------+-------------------+-------------------------------------------+------------+\n| users             | users_chk_1       | (` + \"`c6`\" + ` <> _latin1\\'foo\\\\\\'s\\')   |  YES       |\n| users             | users_chk_2       | (c1 <> _latin1\\'dev/atlas\\')              |  YES       |\n| users             | users_chk_3       | (c1 <> _latin1\\'a\\\\\\'b\"\"\\')               |  YES       |\n| users             | users_chk_4       | (c1 <> in (_latin1\\'usa\\',_latin1\\'uk\\')) |  YES       |\n| users             | users_chk_5       | (c1 <> _latin1\\'\\\\\\\\\\\\\\\\\\\\\\'\\\\\\'\\')       |  YES       |\n+-------------------+-------------------+-------------------------------------------+------------+\n`))\n\t\t\t\tm.ExpectQuery(sqltest.Escape(\"SHOW CREATE TABLE `public`.`users`\")).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+-------+------------------------+\n| Table | Create Table           |\n+-------+------------------------+\n| users | CREATE TABLE users()   |\n+-------+------------------------+\n`))\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.Equal(\"public\", t.Schema.Name)\n\t\t\t\tcolumns := []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t}\n\t\t\t\trequire.EqualValues(columns, t.Columns)\n\t\t\t\trequire.EqualValues([]schema.Attr{\n\t\t\t\t\t&schema.Check{Name: \"users_chk_1\", Expr: \"(`c6` <> _latin1'foo\\\\'s')\"},\n\t\t\t\t\t&schema.Check{Name: \"users_chk_2\", Expr: \"(c1 <> _latin1'dev/atlas')\"},\n\t\t\t\t\t&schema.Check{Name: \"users_chk_3\", Expr: `(c1 <> _latin1'a\\'b\"\"')`},\n\t\t\t\t\t&schema.Check{Name: \"users_chk_4\", Expr: `(c1 <> in (_latin1'usa',_latin1'uk'))`},\n\t\t\t\t\t&schema.Check{Name: \"users_chk_5\", Expr: `(c1 <> _latin1'\\\\\\\\\\'\\'')`},\n\t\t\t\t}, t.Attrs)\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdb, m, err := sqlmock.New()\n\t\t\trequire.NoError(t, err)\n\t\t\tmk := mock{m}\n\t\t\tif tt.version == \"\" {\n\t\t\t\ttt.version = \"8.0.13\"\n\t\t\t}\n\t\t\tmk.version(tt.version)\n\t\t\tmk.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, \"= ?\"))).\n\t\t\t\tWithArgs(\"public\").\n\t\t\t\tWillReturnRows(sqltest.Rows(`\n+-------------+----------------------------+------------------------+\n| SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME |\n+-------------+----------------------------+------------------------+\n| public      | utf8mb4                    | utf8mb4_unicode_ci     |\n+-------------+----------------------------+------------------------+\n\t\t\t\t`))\n\t\t\ttt.before(mk)\n\t\t\tdrv, err := Open(db)\n\t\t\trequire.NoError(t, err)\n\t\t\ts, err := drv.InspectSchema(context.Background(), \"public\", &schema.InspectOptions{\n\t\t\t\tMode: ^schema.InspectViews,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, s)\n\t\t\ttt.expect(require.New(t), s.Tables[0], err)\n\t\t})\n\t}\n}\n\nfunc TestDriver_InspectSchema(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tschema string\n\t\tbefore func(mock)\n\t\texpect func(*require.Assertions, *schema.Schema, error)\n\t}{\n\t\t{\n\t\t\tname: \"attached schema\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.version(\"5.7.23\")\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, \"= SCHEMA()\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+-------------+----------------------------+------------------------+\n| SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME |\n+-------------+----------------------------+------------------------+\n| public      | utf8mb4                    | utf8mb4_unicode_ci     |\n+-------------+----------------------------+------------------------+\n\t\t\t\t`))\n\t\t\t\tm.tables(\"public\")\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, s *schema.Schema, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.EqualValues(func() *schema.Schema {\n\t\t\t\t\trealm := &schema.Realm{\n\t\t\t\t\t\tSchemas: []*schema.Schema{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t\t\t\t\t\t&schema.Collation{V: \"utf8mb4_unicode_ci\"},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{\n\t\t\t\t\t\t\t\tV: \"utf8\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.Collation{\n\t\t\t\t\t\t\t\tV: \"utf8_general_ci\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\trealm.Schemas[0].Realm = realm\n\t\t\t\t\treturn realm.Schemas[0]\n\t\t\t\t}(), s)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"multi table\",\n\t\t\tschema: \"public\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.version(\"8.0.13\")\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, \"= ?\"))).\n\t\t\t\t\tWithArgs(\"public\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+-------------+----------------------------+------------------------+\n| SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME |\n+-------------+----------------------------+------------------------+\n| public      | utf8mb4                    | utf8mb4_unicode_ci     |\n+-------------+----------------------------+------------------------+\n`))\n\t\t\t\tm.tables(\"public\", \"users\", \"pets\")\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(columnsExprQuery, \"?, ?\"))).\n\t\t\t\t\tWithArgs(\"public\", \"users\", \"pets\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+-------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n| TABLE_NAME  | COLUMN_NAME | COLUMN_TYPE  | COLUMN_COMMENT | IS_NULLABLE | COLUMN_KEY | COLUMN_DEFAULT | EXTRA          | CHARACTER_SET_NAME | COLLATION_NAME     | GENERATION_EXPRESSION     |\n+-------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n| users       | id          | int          |                | NO          | PRI        | NULL           |                | NULL               | NULL               | NULL                      |\n| users       | spouse_id   | int          |                | YES         | NULL       | NULL           |                | NULL               | NULL               | NULL                      |\n| pets        | id          | int          |                | NO          | PRI        | NULL           |                | NULL               | NULL               | NULL                      |\n| pets        | owner_id    | int          |                | YES         | NULL       | NULL           |                | NULL               | NULL               | NULL                      |\n+-------------+-------------+--------------+----------------+-------------+------------+----------------+----------------+--------------------+--------------------+---------------------------+\n\t\t\t\t`))\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexesExprQuery, \"?, ?\"))).\n\t\t\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_name\", \"index_name\", \"column_name\", \"non_unique\", \"key_part\", \"expression\"}))\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(fksQuery, \"?, ?\"))).\n\t\t\t\t\tWithArgs(\"public\", \"public\", \"users\", \"pets\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n+------------------+------------+-------------+--------------+-----------------------+------------------------+------------------------+-------------+-------------+\n| CONSTRAINT_NAME  | TABLE_NAME | COLUMN_NAME | TABLE_SCHEMA | REFERENCED_TABLE_NAME | REFERENCED_COLUMN_NAME | REFERENCED_SCHEMA_NAME | UPDATE_RULE | DELETE_RULE |\n+------------------+------------+-------------+--------------+-----------------------+------------------------+------------------------+-------------+-------------+\n| spouse_id        | users      | spouse_id   | public       | users                 | id                     | public                 | NO ACTION   | CASCADE     |\n| owner_id         | pets       | owner_id    | public       | users                 | id                     | public                 | NO ACTION   | CASCADE     |\n+------------------+------------+-------------+--------------+-----------------------+------------------------+------------------------+-------------+-------------+\n\t\t\t\t`))\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, s *schema.Schema, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\tts := s.Tables\n\t\t\t\trequire.Len(ts, 2)\n\t\t\t\tusers, pets := ts[0], ts[1]\n\n\t\t\t\trequire.Equal(\"users\", users.Name)\n\t\t\t\tuserFKs := []*schema.ForeignKey{\n\t\t\t\t\t{Symbol: \"spouse_id\", Table: users, OnUpdate: schema.NoAction, OnDelete: schema.Cascade, RefTable: users},\n\t\t\t\t}\n\t\t\t\tuserColumns := []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t{Name: \"spouse_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}, Null: true}, ForeignKeys: userFKs},\n\t\t\t\t}\n\t\t\t\tuserFKs[0].Columns = userColumns[1:]\n\t\t\t\tuserFKs[0].RefColumns = userColumns[:1]\n\t\t\t\trequire.EqualValues(userColumns, users.Columns)\n\t\t\t\trequire.EqualValues(userFKs, users.ForeignKeys)\n\n\t\t\t\trequire.Equal(\"pets\", pets.Name)\n\t\t\t\tpetsFKs := []*schema.ForeignKey{\n\t\t\t\t\t{Symbol: \"owner_id\", Table: pets, OnUpdate: schema.NoAction, OnDelete: schema.Cascade, RefTable: users, RefColumns: userColumns[:1]},\n\t\t\t\t}\n\t\t\t\tpetsColumns := []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t{Name: \"owner_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}, Null: true}, ForeignKeys: petsFKs},\n\t\t\t\t}\n\t\t\t\tpetsFKs[0].Columns = petsColumns[1:]\n\t\t\t\trequire.EqualValues(petsColumns, pets.Columns)\n\t\t\t\trequire.EqualValues(petsFKs, pets.ForeignKeys)\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdb, m, err := sqlmock.New()\n\t\t\trequire.NoError(t, err)\n\t\t\ttt.before(mock{m})\n\t\t\tdrv, err := Open(db)\n\t\t\trequire.NoError(t, err)\n\t\t\ttables, err := drv.InspectSchema(context.Background(), tt.schema, &schema.InspectOptions{\n\t\t\t\tMode: ^schema.InspectViews,\n\t\t\t})\n\t\t\ttt.expect(require.New(t), tables, err)\n\t\t})\n\t}\n}\n\nfunc TestDriver_Realm(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmk := mock{m}\n\tmk.version(\"8.0.13\")\n\tmk.ExpectQuery(sqltest.Escape(schemasQuery)).\n\t\tWillReturnRows(sqltest.Rows(`\n+-------------+----------------------------+------------------------+\n| SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME |\n+-------------+----------------------------+------------------------+\n| test        | utf8mb4                    | utf8mb4_unicode_ci     |\n+-------------+----------------------------+------------------------+\n`))\n\tmk.tables(\"test\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\trealm, err := drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\tMode: ^schema.InspectViews,\n\t})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, func() *schema.Realm {\n\t\tr := &schema.Realm{\n\t\t\tSchemas: []*schema.Schema{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t\t\t&schema.Collation{V: \"utf8mb4_unicode_ci\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t// Server default configuration.\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Charset{\n\t\t\t\t\tV: \"utf8\",\n\t\t\t\t},\n\t\t\t\t&schema.Collation{\n\t\t\t\t\tV: \"utf8_general_ci\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tr.Schemas[0].Realm = r\n\t\treturn r\n\t}(), realm)\n\n\tmk.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, \"IN (?, ?)\"))).\n\t\tWithArgs(\"test\", \"public\").\n\t\tWillReturnRows(sqltest.Rows(`\n+-------------+----------------------------+------------------------+\n| SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME |\n+-------------+----------------------------+------------------------+\n| test        | utf8mb4                    | utf8mb4_unicode_ci     |\n| public      | utf8                       | utf8_general_ci        |\n+-------------+----------------------------+------------------------+\n`))\n\tmk.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, \"?, ?\"))).\n\t\tWithArgs(\"test\", \"public\").\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"schema\", \"table\", \"charset\", \"collate\", \"inc\", \"comment\", \"options\"}))\n\trealm, err = drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\tMode:    ^schema.InspectViews,\n\t\tSchemas: []string{\"test\", \"public\"},\n\t})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, func() *schema.Realm {\n\t\tr := &schema.Realm{\n\t\t\tSchemas: []*schema.Schema{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t\t\t&schema.Collation{V: \"utf8mb4_unicode_ci\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"public\",\n\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t&schema.Charset{V: \"utf8\"},\n\t\t\t\t\t\t&schema.Collation{V: \"utf8_general_ci\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t// Server default configuration.\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Charset{\n\t\t\t\t\tV: \"utf8\",\n\t\t\t\t},\n\t\t\t\t&schema.Collation{\n\t\t\t\t\tV: \"utf8_general_ci\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tr.Schemas[0].Realm = r\n\t\tr.Schemas[1].Realm = r\n\t\treturn r\n\t}(), realm)\n}\n\nfunc TestInspectMode_InspectRealm(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmk := mock{m}\n\tmk.version(\"8.0.13\")\n\tmk.ExpectQuery(sqltest.Escape(schemasQuery)).\n\t\tWillReturnRows(sqltest.Rows(`\n+-------------+----------------------------+------------------------+\n| SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME |\n+-------------+----------------------------+------------------------+\n| test        | latin1                     | lain1_ci               |\n+-------------+----------------------------+------------------------+\n`))\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\trealm, err := drv.InspectRealm(context.Background(), &schema.InspectRealmOption{Mode: schema.InspectSchemas})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, func() *schema.Realm {\n\t\tr := &schema.Realm{\n\t\t\tSchemas: []*schema.Schema{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t&schema.Collation{V: \"lain1_ci\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t// Server default configuration.\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Charset{\n\t\t\t\t\tV: \"utf8\",\n\t\t\t\t},\n\t\t\t\t&schema.Collation{\n\t\t\t\t\tV: \"utf8_general_ci\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tr.Schemas[0].Realm = r\n\t\treturn r\n\t}(), realm)\n}\n\ntype mock struct {\n\tsqlmock.Sqlmock\n}\n\nfunc (m mock) version(version string) {\n\tm.ExpectQuery(sqltest.Escape(variablesQuery)).\n\t\tWillReturnRows(sqltest.Rows(`\n+-----------------+--------------------+------------------------+--------------------------+ \n| @@version       | @@collation_server | @@character_set_server | @@lower_case_table_names | \n+-----------------+--------------------+------------------------+--------------------------+ \n| ` + version + ` | utf8_general_ci    | utf8                   | 0                        | \n+-----------------+--------------------+------------------------+--------------------------+ \n`))\n}\n\nfunc (m mock) lcmode(version, mode string) {\n\tm.ExpectQuery(sqltest.Escape(variablesQuery)).\n\t\tWillReturnRows(sqltest.Rows(`\n+-----------------+--------------------+------------------------+--------------------------+ \n| @@version       | @@collation_server | @@character_set_server | @@lower_case_table_names | \n+-----------------+--------------------+------------------------+--------------------------+ \n| ` + version + ` | utf8_general_ci    | utf8                   | ` + mode + `             |\n+-----------------+--------------------+------------------------+--------------------------+ \n`))\n}\n\nfunc (m mock) noIndexes() {\n\tm.ExpectQuery(queryIndexesExpr).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_name\", \"index_name\", \"column_name\", \"non_unique\", \"key_part\", \"expression\"}))\n}\n\nfunc (m mock) noFKs() {\n\tm.ExpectQuery(queryFKs).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"TABLE_NAME\", \"CONSTRAINT_NAME\", \"TABLE_NAME\", \"COLUMN_NAME\", \"REFERENCED_TABLE_NAME\", \"REFERENCED_COLUMN_NAME\", \"REFERENCED_TABLE_SCHEMA\", \"UPDATE_RULE\", \"DELETE_RULE\"}))\n}\n\nfunc (m mock) tableExists(schema, table string, exists bool) {\n\trows := sqlmock.NewRows([]string{\"table_schema\", \"table_name\", \"table_collation\", \"character_set\", \"auto_increment\", \"table_comment\", \"create_options\", \"engine\", \"default_engine\", \"table_type\"})\n\tif exists {\n\t\trows.AddRow(schema, table, nil, nil, nil, nil, nil, nil, nil, nil)\n\t}\n\tm.ExpectQuery(queryTable).\n\t\tWithArgs(schema).\n\t\tWillReturnRows(rows)\n}\n\nfunc (m mock) tables(schema string, tables ...string) {\n\trows := sqlmock.NewRows([]string{\"schema\", \"table\", \"charset\", \"collate\", \"inc\", \"comment\", \"options\", \"engine\", \"default_engine\", \"table_type\"})\n\tfor _, t := range tables {\n\t\trows.AddRow(schema, t, nil, nil, nil, nil, nil, nil, nil, nil)\n\t}\n\tm.ExpectQuery(queryTable).\n\t\tWithArgs(schema).\n\t\tWillReturnRows(rows)\n}\n"
  },
  {
    "path": "sql/mysql/internal/mysqlversion/is/.README.md",
    "content": "## Charset and Collation of MySQL and MariaDB latest versions\n\n`collate2charset` and `collate2charset.maria` hold a mapping from the collation to their charset.\n\n```sql\nselect json_objectagg(collation_name, character_set_name) from information_schema.collations\\G;\n```\n\n`charset2collate` and `charset2collate.maria` hold a mapping from the charset to its default collation extracted\nby the following query:\n\n```sql\nselect json_objectagg(character_set_name, default_collate_name) from information_schema.character_sets\\G;\n```"
  },
  {
    "path": "sql/mysql/internal/mysqlversion/is/charset2collate",
    "content": "{\"gbk\": \"gbk_chinese_ci\", \"hp8\": \"hp8_english_ci\", \"big5\": \"big5_chinese_ci\", \"dec8\": \"dec8_swedish_ci\", \"sjis\": \"sjis_japanese_ci\", \"swe7\": \"swe7_swedish_ci\", \"ucs2\": \"ucs2_general_ci\", \"ujis\": \"ujis_japanese_ci\", \"ascii\": \"ascii_general_ci\", \"cp850\": \"cp850_general_ci\", \"cp852\": \"cp852_general_ci\", \"cp866\": \"cp866_general_ci\", \"cp932\": \"cp932_japanese_ci\", \"euckr\": \"euckr_korean_ci\", \"greek\": \"greek_general_ci\", \"koi8r\": \"koi8r_general_ci\", \"koi8u\": \"koi8u_general_ci\", \"macce\": \"macce_general_ci\", \"utf16\": \"utf16_general_ci\", \"utf32\": \"utf32_general_ci\", \"binary\": \"binary\", \"cp1250\": \"cp1250_general_ci\", \"cp1251\": \"cp1251_general_ci\", \"cp1256\": \"cp1256_general_ci\", \"cp1257\": \"cp1257_general_ci\", \"gb2312\": \"gb2312_chinese_ci\", \"hebrew\": \"hebrew_general_ci\", \"latin1\": \"latin1_swedish_ci\", \"latin2\": \"latin2_general_ci\", \"latin5\": \"latin5_turkish_ci\", \"latin7\": \"latin7_general_ci\", \"tis620\": \"tis620_thai_ci\", \"eucjpms\": \"eucjpms_japanese_ci\", \"gb18030\": \"gb18030_chinese_ci\", \"geostd8\": \"geostd8_general_ci\", \"keybcs2\": \"keybcs2_general_ci\", \"utf16le\": \"utf16le_general_ci\", \"utf8mb3\": \"utf8mb3_general_ci\", \"utf8mb4\": \"utf8mb4_0900_ai_ci\", \"armscii8\": \"armscii8_general_ci\", \"macroman\": \"macroman_general_ci\",\"utf8\": \"utf8_general_ci\"}"
  },
  {
    "path": "sql/mysql/internal/mysqlversion/is/charset2collate.maria",
    "content": "{\"big5\":\"big5_chinese_ci\", \"dec8\":\"dec8_swedish_ci\", \"cp850\":\"cp850_general_ci\", \"hp8\":\"hp8_english_ci\", \"koi8r\":\"koi8r_general_ci\", \"latin1\":\"latin1_swedish_ci\", \"latin2\":\"latin2_general_ci\", \"swe7\":\"swe7_swedish_ci\", \"ascii\":\"ascii_general_ci\", \"ujis\":\"ujis_japanese_ci\", \"sjis\":\"sjis_japanese_ci\", \"hebrew\":\"hebrew_general_ci\", \"tis620\":\"tis620_thai_ci\", \"euckr\":\"euckr_korean_ci\", \"koi8u\":\"koi8u_general_ci\", \"gb2312\":\"gb2312_chinese_ci\", \"greek\":\"greek_general_ci\", \"cp1250\":\"cp1250_general_ci\", \"gbk\":\"gbk_chinese_ci\", \"latin5\":\"latin5_turkish_ci\", \"armscii8\":\"armscii8_general_ci\", \"utf8mb3\":\"utf8mb3_general_ci\", \"ucs2\":\"ucs2_general_ci\", \"cp866\":\"cp866_general_ci\", \"keybcs2\":\"keybcs2_general_ci\", \"macce\":\"macce_general_ci\", \"macroman\":\"macroman_general_ci\", \"cp852\":\"cp852_general_ci\", \"latin7\":\"latin7_general_ci\", \"utf8mb4\":\"utf8mb4_general_ci\", \"cp1251\":\"cp1251_general_ci\", \"utf16\":\"utf16_general_ci\", \"utf16le\":\"utf16le_general_ci\", \"cp1256\":\"cp1256_general_ci\", \"cp1257\":\"cp1257_general_ci\", \"utf32\":\"utf32_general_ci\", \"binary\":\"binary\", \"geostd8\":\"geostd8_general_ci\", \"cp932\":\"cp932_japanese_ci\", \"eucjpms\":\"eucjpms_japanese_ci\"}"
  },
  {
    "path": "sql/mysql/internal/mysqlversion/is/collate2charset",
    "content": "{\"binary\": \"binary\", \"gbk_bin\": \"gbk\", \"hp8_bin\": \"hp8\", \"big5_bin\": \"big5\", \"dec8_bin\": \"dec8\", \"sjis_bin\": \"sjis\", \"swe7_bin\": \"swe7\", \"ucs2_bin\": \"ucs2\", \"ujis_bin\": \"ujis\", \"ascii_bin\": \"ascii\", \"cp850_bin\": \"cp850\", \"cp852_bin\": \"cp852\", \"cp866_bin\": \"cp866\", \"cp932_bin\": \"cp932\", \"euckr_bin\": \"euckr\", \"greek_bin\": \"greek\", \"koi8r_bin\": \"koi8r\", \"koi8u_bin\": \"koi8u\", \"macce_bin\": \"macce\", \"utf16_bin\": \"utf16\", \"utf32_bin\": \"utf32\", \"cp1250_bin\": \"cp1250\", \"cp1251_bin\": \"cp1251\", \"cp1256_bin\": \"cp1256\", \"cp1257_bin\": \"cp1257\", \"gb2312_bin\": \"gb2312\", \"hebrew_bin\": \"hebrew\", \"latin1_bin\": \"latin1\", \"latin2_bin\": \"latin2\", \"latin5_bin\": \"latin5\", \"latin7_bin\": \"latin7\", \"tis620_bin\": \"tis620\", \"eucjpms_bin\": \"eucjpms\", \"gb18030_bin\": \"gb18030\", \"geostd8_bin\": \"geostd8\", \"keybcs2_bin\": \"keybcs2\", \"utf16le_bin\": \"utf16le\", \"utf8mb3_bin\": \"utf8mb3\", \"utf8mb4_bin\": \"utf8mb4\", \"armscii8_bin\": \"armscii8\", \"macroman_bin\": \"macroman\", \"ucs2_czech_ci\": \"ucs2\", \"ucs2_roman_ci\": \"ucs2\", \"gbk_chinese_ci\": \"gbk\", \"hp8_english_ci\": \"hp8\", \"tis620_thai_ci\": \"tis620\", \"ucs2_danish_ci\": \"ucs2\", \"ucs2_polish_ci\": \"ucs2\", \"ucs2_slovak_ci\": \"ucs2\", \"utf16_czech_ci\": \"utf16\", \"utf16_roman_ci\": \"utf16\", \"utf32_czech_ci\": \"utf32\", \"utf32_roman_ci\": \"utf32\", \"big5_chinese_ci\": \"big5\", \"cp1250_czech_cs\": \"cp1250\", \"dec8_swedish_ci\": \"dec8\", \"euckr_korean_ci\": \"euckr\", \"latin2_czech_cs\": \"latin2\", \"swe7_swedish_ci\": \"swe7\", \"ucs2_general_ci\": \"ucs2\", \"ucs2_german2_ci\": \"ucs2\", \"ucs2_latvian_ci\": \"ucs2\", \"ucs2_persian_ci\": \"ucs2\", \"ucs2_sinhala_ci\": \"ucs2\", \"ucs2_spanish_ci\": \"ucs2\", \"ucs2_swedish_ci\": \"ucs2\", \"ucs2_turkish_ci\": \"ucs2\", \"ucs2_unicode_ci\": \"ucs2\", \"utf16_danish_ci\": \"utf16\", \"utf16_polish_ci\": \"utf16\", \"utf16_slovak_ci\": \"utf16\", \"utf32_danish_ci\": \"utf32\", \"utf32_polish_ci\": \"utf32\", \"utf32_slovak_ci\": \"utf32\", \"ascii_general_ci\": \"ascii\", \"cp1250_polish_ci\": \"cp1250\", \"cp850_general_ci\": \"cp850\", \"cp852_general_ci\": \"cp852\", \"cp866_general_ci\": \"cp866\", \"greek_general_ci\": \"greek\", \"koi8r_general_ci\": \"koi8r\", \"koi8u_general_ci\": \"koi8u\", \"latin1_danish_ci\": \"latin1\", \"macce_general_ci\": \"macce\", \"sjis_japanese_ci\": \"sjis\", \"ucs2_croatian_ci\": \"ucs2\", \"ucs2_estonian_ci\": \"ucs2\", \"ucs2_romanian_ci\": \"ucs2\", \"ucs2_spanish2_ci\": \"ucs2\", \"ujis_japanese_ci\": \"ujis\", \"utf16_general_ci\": \"utf16\", \"utf16_german2_ci\": \"utf16\", \"utf16_latvian_ci\": \"utf16\", \"utf16_persian_ci\": \"utf16\", \"utf16_sinhala_ci\": \"utf16\", \"utf16_spanish_ci\": \"utf16\", \"utf16_swedish_ci\": \"utf16\", \"utf16_turkish_ci\": \"utf16\", \"utf16_unicode_ci\": \"utf16\", \"utf32_general_ci\": \"utf32\", \"utf32_german2_ci\": \"utf32\", \"utf32_latvian_ci\": \"utf32\", \"utf32_persian_ci\": \"utf32\", \"utf32_sinhala_ci\": \"utf32\", \"utf32_spanish_ci\": \"utf32\", \"utf32_swedish_ci\": \"utf32\", \"utf32_turkish_ci\": \"utf32\", \"utf32_unicode_ci\": \"utf32\", \"utf8mb3_czech_ci\": \"utf8mb3\", \"utf8mb3_roman_ci\": \"utf8mb3\", \"utf8mb4_0900_bin\": \"utf8mb4\", \"utf8mb4_czech_ci\": \"utf8mb4\", \"utf8mb4_roman_ci\": \"utf8mb4\", \"cp1250_general_ci\": \"cp1250\", \"cp1251_general_ci\": \"cp1251\", \"cp1251_general_cs\": \"cp1251\", \"cp1256_general_ci\": \"cp1256\", \"cp1257_general_ci\": \"cp1257\", \"cp932_japanese_ci\": \"cp932\", \"gb2312_chinese_ci\": \"gb2312\", \"hebrew_general_ci\": \"hebrew\", \"latin1_general_ci\": \"latin1\", \"latin1_general_cs\": \"latin1\", \"latin1_german1_ci\": \"latin1\", \"latin1_german2_ci\": \"latin1\", \"latin1_spanish_ci\": \"latin1\", \"latin1_swedish_ci\": \"latin1\", \"latin2_general_ci\": \"latin2\", \"latin5_turkish_ci\": \"latin5\", \"latin7_general_ci\": \"latin7\", \"latin7_general_cs\": \"latin7\", \"ucs2_esperanto_ci\": \"ucs2\", \"ucs2_hungarian_ci\": \"ucs2\", \"ucs2_icelandic_ci\": \"ucs2\", \"ucs2_slovenian_ci\": \"ucs2\", \"utf16_croatian_ci\": \"utf16\", \"utf16_estonian_ci\": \"utf16\", \"utf16_romanian_ci\": \"utf16\", \"utf16_spanish2_ci\": \"utf16\", \"utf32_croatian_ci\": \"utf32\", \"utf32_estonian_ci\": \"utf32\", \"utf32_romanian_ci\": \"utf32\", \"utf32_spanish2_ci\": \"utf32\", \"utf8mb3_danish_ci\": \"utf8mb3\", \"utf8mb3_polish_ci\": \"utf8mb3\", \"utf8mb3_slovak_ci\": \"utf8mb3\", \"utf8mb4_danish_ci\": \"utf8mb4\", \"utf8mb4_polish_ci\": \"utf8mb4\", \"utf8mb4_slovak_ci\": \"utf8mb4\", \"cp1250_croatian_ci\": \"cp1250\", \"gb18030_chinese_ci\": \"gb18030\", \"geostd8_general_ci\": \"geostd8\", \"keybcs2_general_ci\": \"keybcs2\", \"latin2_croatian_ci\": \"latin2\", \"latin7_estonian_cs\": \"latin7\", \"ucs2_lithuanian_ci\": \"ucs2\", \"ucs2_vietnamese_ci\": \"ucs2\", \"utf16_esperanto_ci\": \"utf16\", \"utf16_hungarian_ci\": \"utf16\", \"utf16_icelandic_ci\": \"utf16\", \"utf16_slovenian_ci\": \"utf16\", \"utf16le_general_ci\": \"utf16le\", \"utf32_esperanto_ci\": \"utf32\", \"utf32_hungarian_ci\": \"utf32\", \"utf32_icelandic_ci\": \"utf32\", \"utf32_slovenian_ci\": \"utf32\", \"utf8mb3_general_ci\": \"utf8mb3\", \"utf8mb3_german2_ci\": \"utf8mb3\", \"utf8mb3_latvian_ci\": \"utf8mb3\", \"utf8mb3_persian_ci\": \"utf8mb3\", \"utf8mb3_sinhala_ci\": \"utf8mb3\", \"utf8mb3_spanish_ci\": \"utf8mb3\", \"utf8mb3_swedish_ci\": \"utf8mb3\", \"utf8mb3_tolower_ci\": \"utf8mb3\", \"utf8mb3_turkish_ci\": \"utf8mb3\", \"utf8mb3_unicode_ci\": \"utf8mb3\", \"utf8mb4_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_0900_as_ci\": \"utf8mb4\", \"utf8mb4_0900_as_cs\": \"utf8mb4\", \"utf8mb4_general_ci\": \"utf8mb4\", \"utf8mb4_german2_ci\": \"utf8mb4\", \"utf8mb4_latvian_ci\": \"utf8mb4\", \"utf8mb4_persian_ci\": \"utf8mb4\", \"utf8mb4_sinhala_ci\": \"utf8mb4\", \"utf8mb4_spanish_ci\": \"utf8mb4\", \"utf8mb4_swedish_ci\": \"utf8mb4\", \"utf8mb4_turkish_ci\": \"utf8mb4\", \"utf8mb4_unicode_ci\": \"utf8mb4\", \"armscii8_general_ci\": \"armscii8\", \"cp1251_bulgarian_ci\": \"cp1251\", \"cp1251_ukrainian_ci\": \"cp1251\", \"eucjpms_japanese_ci\": \"eucjpms\", \"latin2_hungarian_ci\": \"latin2\", \"macroman_general_ci\": \"macroman\", \"ucs2_unicode_520_ci\": \"ucs2\", \"utf16_lithuanian_ci\": \"utf16\", \"utf16_vietnamese_ci\": \"utf16\", \"utf32_lithuanian_ci\": \"utf32\", \"utf32_vietnamese_ci\": \"utf32\", \"utf8mb3_croatian_ci\": \"utf8mb3\", \"utf8mb3_estonian_ci\": \"utf8mb3\", \"utf8mb3_romanian_ci\": \"utf8mb3\", \"utf8mb3_spanish2_ci\": \"utf8mb3\", \"utf8mb4_croatian_ci\": \"utf8mb4\", \"utf8mb4_estonian_ci\": \"utf8mb4\", \"utf8mb4_romanian_ci\": \"utf8mb4\", \"utf8mb4_spanish2_ci\": \"utf8mb4\", \"cp1257_lithuanian_ci\": \"cp1257\", \"utf16_unicode_520_ci\": \"utf16\", \"utf32_unicode_520_ci\": \"utf32\", \"utf8mb3_esperanto_ci\": \"utf8mb3\", \"utf8mb3_hungarian_ci\": \"utf8mb3\", \"utf8mb3_icelandic_ci\": \"utf8mb3\", \"utf8mb3_slovenian_ci\": \"utf8mb3\", \"utf8mb4_esperanto_ci\": \"utf8mb4\", \"utf8mb4_hungarian_ci\": \"utf8mb4\", \"utf8mb4_icelandic_ci\": \"utf8mb4\", \"utf8mb4_slovenian_ci\": \"utf8mb4\", \"utf8mb3_lithuanian_ci\": \"utf8mb3\", \"utf8mb3_vietnamese_ci\": \"utf8mb3\", \"utf8mb4_bg_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_bg_0900_as_cs\": \"utf8mb4\", \"utf8mb4_bs_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_bs_0900_as_cs\": \"utf8mb4\", \"utf8mb4_cs_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_cs_0900_as_cs\": \"utf8mb4\", \"utf8mb4_da_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_da_0900_as_cs\": \"utf8mb4\", \"utf8mb4_eo_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_eo_0900_as_cs\": \"utf8mb4\", \"utf8mb4_es_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_es_0900_as_cs\": \"utf8mb4\", \"utf8mb4_et_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_et_0900_as_cs\": \"utf8mb4\", \"utf8mb4_gl_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_gl_0900_as_cs\": \"utf8mb4\", \"utf8mb4_hr_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_hr_0900_as_cs\": \"utf8mb4\", \"utf8mb4_hu_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_hu_0900_as_cs\": \"utf8mb4\", \"utf8mb4_is_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_is_0900_as_cs\": \"utf8mb4\", \"utf8mb4_ja_0900_as_cs\": \"utf8mb4\", \"utf8mb4_la_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_la_0900_as_cs\": \"utf8mb4\", \"utf8mb4_lithuanian_ci\": \"utf8mb4\", \"utf8mb4_lt_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_lt_0900_as_cs\": \"utf8mb4\", \"utf8mb4_lv_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_lv_0900_as_cs\": \"utf8mb4\", \"utf8mb4_nb_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_nb_0900_as_cs\": \"utf8mb4\", \"utf8mb4_nn_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_nn_0900_as_cs\": \"utf8mb4\", \"utf8mb4_pl_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_pl_0900_as_cs\": \"utf8mb4\", \"utf8mb4_ro_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_ro_0900_as_cs\": \"utf8mb4\", \"utf8mb4_ru_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_ru_0900_as_cs\": \"utf8mb4\", \"utf8mb4_sk_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_sk_0900_as_cs\": \"utf8mb4\", \"utf8mb4_sl_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_sl_0900_as_cs\": \"utf8mb4\", \"utf8mb4_sv_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_sv_0900_as_cs\": \"utf8mb4\", \"utf8mb4_tr_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_tr_0900_as_cs\": \"utf8mb4\", \"utf8mb4_vi_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_vi_0900_as_cs\": \"utf8mb4\", \"utf8mb4_vietnamese_ci\": \"utf8mb4\", \"utf8mb4_zh_0900_as_cs\": \"utf8mb4\", \"gb18030_unicode_520_ci\": \"gb18030\", \"utf8mb3_unicode_520_ci\": \"utf8mb3\", \"utf8mb4_unicode_520_ci\": \"utf8mb4\", \"ucs2_general_mysql500_ci\": \"ucs2\", \"utf8mb4_de_pb_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_de_pb_0900_as_cs\": \"utf8mb4\", \"utf8mb4_ja_0900_as_cs_ks\": \"utf8mb4\", \"utf8mb4_es_trad_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_es_trad_0900_as_cs\": \"utf8mb4\", \"utf8mb4_mn_cyrl_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_mn_cyrl_0900_as_cs\": \"utf8mb4\", \"utf8mb4_sr_latn_0900_ai_ci\": \"utf8mb4\", \"utf8mb4_sr_latn_0900_as_cs\": \"utf8mb4\", \"utf8mb3_general_mysql500_ci\": \"utf8mb3\", \"utf8_bin\": \"utf8\", \"utf8_croatian_ci\": \"utf8\", \"utf8_czech_ci\": \"utf8\", \"utf8_danish_ci\": \"utf8\", \"utf8_esperanto_ci\": \"utf8\", \"utf8_estonian_ci\": \"utf8\", \"utf8_general_ci\": \"utf8\", \"utf8_general_mysql500_ci\": \"utf8\", \"utf8_german2_ci\": \"utf8\", \"utf8_hungarian_ci\": \"utf8\", \"utf8_icelandic_ci\": \"utf8\", \"utf8_latvian_ci\": \"utf8\", \"utf8_lithuanian_ci\": \"utf8\", \"utf8_persian_ci\": \"utf8\", \"utf8_polish_ci\": \"utf8\", \"utf8_roman_ci\": \"utf8\", \"utf8_romanian_ci\": \"utf8\", \"utf8_sinhala_ci\": \"utf8\", \"utf8_slovak_ci\": \"utf8\", \"utf8_slovenian_ci\": \"utf8\", \"utf8_spanish_ci\": \"utf8\", \"utf8_spanish2_ci\": \"utf8\", \"utf8_swedish_ci\": \"utf8\", \"utf8_tolower_ci\": \"utf8\", \"utf8_turkish_ci\": \"utf8\", \"utf8_unicode_520_ci\": \"utf8\", \"utf8_unicode_ci\": \"utf8\", \"utf8_vietnamese_ci\": \"utf8\"}"
  },
  {
    "path": "sql/mysql/internal/mysqlversion/is/collate2charset.maria",
    "content": "{\"big5_chinese_ci\":\"big5\", \"big5_bin\":\"big5\", \"big5_chinese_nopad_ci\":\"big5\", \"big5_nopad_bin\":\"big5\", \"dec8_swedish_ci\":\"dec8\", \"dec8_bin\":\"dec8\", \"dec8_swedish_nopad_ci\":\"dec8\", \"dec8_nopad_bin\":\"dec8\", \"cp850_general_ci\":\"cp850\", \"cp850_bin\":\"cp850\", \"cp850_general_nopad_ci\":\"cp850\", \"cp850_nopad_bin\":\"cp850\", \"hp8_english_ci\":\"hp8\", \"hp8_bin\":\"hp8\", \"hp8_english_nopad_ci\":\"hp8\", \"hp8_nopad_bin\":\"hp8\", \"koi8r_general_ci\":\"koi8r\", \"koi8r_bin\":\"koi8r\", \"koi8r_general_nopad_ci\":\"koi8r\", \"koi8r_nopad_bin\":\"koi8r\", \"latin1_german1_ci\":\"latin1\", \"latin1_swedish_ci\":\"latin1\", \"latin1_danish_ci\":\"latin1\", \"latin1_german2_ci\":\"latin1\", \"latin1_bin\":\"latin1\", \"latin1_general_ci\":\"latin1\", \"latin1_general_cs\":\"latin1\", \"latin1_spanish_ci\":\"latin1\", \"latin1_swedish_nopad_ci\":\"latin1\", \"latin1_nopad_bin\":\"latin1\", \"latin2_czech_cs\":\"latin2\", \"latin2_general_ci\":\"latin2\", \"latin2_hungarian_ci\":\"latin2\", \"latin2_croatian_ci\":\"latin2\", \"latin2_bin\":\"latin2\", \"latin2_general_nopad_ci\":\"latin2\", \"latin2_nopad_bin\":\"latin2\", \"swe7_swedish_ci\":\"swe7\", \"swe7_bin\":\"swe7\", \"swe7_swedish_nopad_ci\":\"swe7\", \"swe7_nopad_bin\":\"swe7\", \"ascii_general_ci\":\"ascii\", \"ascii_bin\":\"ascii\", \"ascii_general_nopad_ci\":\"ascii\", \"ascii_nopad_bin\":\"ascii\", \"ujis_japanese_ci\":\"ujis\", \"ujis_bin\":\"ujis\", \"ujis_japanese_nopad_ci\":\"ujis\", \"ujis_nopad_bin\":\"ujis\", \"sjis_japanese_ci\":\"sjis\", \"sjis_bin\":\"sjis\", \"sjis_japanese_nopad_ci\":\"sjis\", \"sjis_nopad_bin\":\"sjis\", \"hebrew_general_ci\":\"hebrew\", \"hebrew_bin\":\"hebrew\", \"hebrew_general_nopad_ci\":\"hebrew\", \"hebrew_nopad_bin\":\"hebrew\", \"tis620_thai_ci\":\"tis620\", \"tis620_bin\":\"tis620\", \"tis620_thai_nopad_ci\":\"tis620\", \"tis620_nopad_bin\":\"tis620\", \"euckr_korean_ci\":\"euckr\", \"euckr_bin\":\"euckr\", \"euckr_korean_nopad_ci\":\"euckr\", \"euckr_nopad_bin\":\"euckr\", \"koi8u_general_ci\":\"koi8u\", \"koi8u_bin\":\"koi8u\", \"koi8u_general_nopad_ci\":\"koi8u\", \"koi8u_nopad_bin\":\"koi8u\", \"gb2312_chinese_ci\":\"gb2312\", \"gb2312_bin\":\"gb2312\", \"gb2312_chinese_nopad_ci\":\"gb2312\", \"gb2312_nopad_bin\":\"gb2312\", \"greek_general_ci\":\"greek\", \"greek_bin\":\"greek\", \"greek_general_nopad_ci\":\"greek\", \"greek_nopad_bin\":\"greek\", \"cp1250_general_ci\":\"cp1250\", \"cp1250_czech_cs\":\"cp1250\", \"cp1250_croatian_ci\":\"cp1250\", \"cp1250_bin\":\"cp1250\", \"cp1250_polish_ci\":\"cp1250\", \"cp1250_general_nopad_ci\":\"cp1250\", \"cp1250_nopad_bin\":\"cp1250\", \"gbk_chinese_ci\":\"gbk\", \"gbk_bin\":\"gbk\", \"gbk_chinese_nopad_ci\":\"gbk\", \"gbk_nopad_bin\":\"gbk\", \"latin5_turkish_ci\":\"latin5\", \"latin5_bin\":\"latin5\", \"latin5_turkish_nopad_ci\":\"latin5\", \"latin5_nopad_bin\":\"latin5\", \"armscii8_general_ci\":\"armscii8\", \"armscii8_bin\":\"armscii8\", \"armscii8_general_nopad_ci\":\"armscii8\", \"armscii8_nopad_bin\":\"armscii8\", \"utf8mb3_general_ci\":\"utf8mb3\", \"utf8mb3_bin\":\"utf8mb3\", \"utf8mb3_unicode_ci\":\"utf8mb3\", \"utf8mb3_icelandic_ci\":\"utf8mb3\", \"utf8mb3_latvian_ci\":\"utf8mb3\", \"utf8mb3_romanian_ci\":\"utf8mb3\", \"utf8mb3_slovenian_ci\":\"utf8mb3\", \"utf8mb3_polish_ci\":\"utf8mb3\", \"utf8mb3_estonian_ci\":\"utf8mb3\", \"utf8mb3_spanish_ci\":\"utf8mb3\", \"utf8mb3_swedish_ci\":\"utf8mb3\", \"utf8mb3_turkish_ci\":\"utf8mb3\", \"utf8mb3_czech_ci\":\"utf8mb3\", \"utf8mb3_danish_ci\":\"utf8mb3\", \"utf8mb3_lithuanian_ci\":\"utf8mb3\", \"utf8mb3_slovak_ci\":\"utf8mb3\", \"utf8mb3_spanish2_ci\":\"utf8mb3\", \"utf8mb3_roman_ci\":\"utf8mb3\", \"utf8mb3_persian_ci\":\"utf8mb3\", \"utf8mb3_esperanto_ci\":\"utf8mb3\", \"utf8mb3_hungarian_ci\":\"utf8mb3\", \"utf8mb3_sinhala_ci\":\"utf8mb3\", \"utf8mb3_german2_ci\":\"utf8mb3\", \"utf8mb3_croatian_mysql561_ci\":\"utf8mb3\", \"utf8mb3_unicode_520_ci\":\"utf8mb3\", \"utf8mb3_vietnamese_ci\":\"utf8mb3\", \"utf8mb3_general_mysql500_ci\":\"utf8mb3\", \"utf8mb3_croatian_ci\":\"utf8mb3\", \"utf8mb3_myanmar_ci\":\"utf8mb3\", \"utf8mb3_thai_520_w2\":\"utf8mb3\", \"utf8mb3_general_nopad_ci\":\"utf8mb3\", \"utf8mb3_nopad_bin\":\"utf8mb3\", \"utf8mb3_unicode_nopad_ci\":\"utf8mb3\", \"utf8mb3_unicode_520_nopad_ci\":\"utf8mb3\", \"ucs2_general_ci\":\"ucs2\", \"ucs2_bin\":\"ucs2\", \"ucs2_unicode_ci\":\"ucs2\", \"ucs2_icelandic_ci\":\"ucs2\", \"ucs2_latvian_ci\":\"ucs2\", \"ucs2_romanian_ci\":\"ucs2\", \"ucs2_slovenian_ci\":\"ucs2\", \"ucs2_polish_ci\":\"ucs2\", \"ucs2_estonian_ci\":\"ucs2\", \"ucs2_spanish_ci\":\"ucs2\", \"ucs2_swedish_ci\":\"ucs2\", \"ucs2_turkish_ci\":\"ucs2\", \"ucs2_czech_ci\":\"ucs2\", \"ucs2_danish_ci\":\"ucs2\", \"ucs2_lithuanian_ci\":\"ucs2\", \"ucs2_slovak_ci\":\"ucs2\", \"ucs2_spanish2_ci\":\"ucs2\", \"ucs2_roman_ci\":\"ucs2\", \"ucs2_persian_ci\":\"ucs2\", \"ucs2_esperanto_ci\":\"ucs2\", \"ucs2_hungarian_ci\":\"ucs2\", \"ucs2_sinhala_ci\":\"ucs2\", \"ucs2_german2_ci\":\"ucs2\", \"ucs2_croatian_mysql561_ci\":\"ucs2\", \"ucs2_unicode_520_ci\":\"ucs2\", \"ucs2_vietnamese_ci\":\"ucs2\", \"ucs2_general_mysql500_ci\":\"ucs2\", \"ucs2_croatian_ci\":\"ucs2\", \"ucs2_myanmar_ci\":\"ucs2\", \"ucs2_thai_520_w2\":\"ucs2\", \"ucs2_general_nopad_ci\":\"ucs2\", \"ucs2_nopad_bin\":\"ucs2\", \"ucs2_unicode_nopad_ci\":\"ucs2\", \"ucs2_unicode_520_nopad_ci\":\"ucs2\", \"cp866_general_ci\":\"cp866\", \"cp866_bin\":\"cp866\", \"cp866_general_nopad_ci\":\"cp866\", \"cp866_nopad_bin\":\"cp866\", \"keybcs2_general_ci\":\"keybcs2\", \"keybcs2_bin\":\"keybcs2\", \"keybcs2_general_nopad_ci\":\"keybcs2\", \"keybcs2_nopad_bin\":\"keybcs2\", \"macce_general_ci\":\"macce\", \"macce_bin\":\"macce\", \"macce_general_nopad_ci\":\"macce\", \"macce_nopad_bin\":\"macce\", \"macroman_general_ci\":\"macroman\", \"macroman_bin\":\"macroman\", \"macroman_general_nopad_ci\":\"macroman\", \"macroman_nopad_bin\":\"macroman\", \"cp852_general_ci\":\"cp852\", \"cp852_bin\":\"cp852\", \"cp852_general_nopad_ci\":\"cp852\", \"cp852_nopad_bin\":\"cp852\", \"latin7_estonian_cs\":\"latin7\", \"latin7_general_ci\":\"latin7\", \"latin7_general_cs\":\"latin7\", \"latin7_bin\":\"latin7\", \"latin7_general_nopad_ci\":\"latin7\", \"latin7_nopad_bin\":\"latin7\", \"utf8mb4_general_ci\":\"utf8mb4\", \"utf8mb4_bin\":\"utf8mb4\", \"utf8mb4_unicode_ci\":\"utf8mb4\", \"utf8mb4_icelandic_ci\":\"utf8mb4\", \"utf8mb4_latvian_ci\":\"utf8mb4\", \"utf8mb4_romanian_ci\":\"utf8mb4\", \"utf8mb4_slovenian_ci\":\"utf8mb4\", \"utf8mb4_polish_ci\":\"utf8mb4\", \"utf8mb4_estonian_ci\":\"utf8mb4\", \"utf8mb4_spanish_ci\":\"utf8mb4\", \"utf8mb4_swedish_ci\":\"utf8mb4\", \"utf8mb4_turkish_ci\":\"utf8mb4\", \"utf8mb4_czech_ci\":\"utf8mb4\", \"utf8mb4_danish_ci\":\"utf8mb4\", \"utf8mb4_lithuanian_ci\":\"utf8mb4\", \"utf8mb4_slovak_ci\":\"utf8mb4\", \"utf8mb4_spanish2_ci\":\"utf8mb4\", \"utf8mb4_roman_ci\":\"utf8mb4\", \"utf8mb4_persian_ci\":\"utf8mb4\", \"utf8mb4_esperanto_ci\":\"utf8mb4\", \"utf8mb4_hungarian_ci\":\"utf8mb4\", \"utf8mb4_sinhala_ci\":\"utf8mb4\", \"utf8mb4_german2_ci\":\"utf8mb4\", \"utf8mb4_croatian_mysql561_ci\":\"utf8mb4\", \"utf8mb4_unicode_520_ci\":\"utf8mb4\", \"utf8mb4_vietnamese_ci\":\"utf8mb4\", \"utf8mb4_croatian_ci\":\"utf8mb4\", \"utf8mb4_myanmar_ci\":\"utf8mb4\", \"utf8mb4_thai_520_w2\":\"utf8mb4\", \"utf8mb4_general_nopad_ci\":\"utf8mb4\", \"utf8mb4_nopad_bin\":\"utf8mb4\", \"utf8mb4_unicode_nopad_ci\":\"utf8mb4\", \"utf8mb4_unicode_520_nopad_ci\":\"utf8mb4\", \"uca1400_ai_ci\":null, \"uca1400_ai_cs\":null, \"uca1400_as_ci\":null, \"uca1400_as_cs\":null, \"uca1400_nopad_ai_ci\":null, \"uca1400_nopad_ai_cs\":null, \"uca1400_nopad_as_ci\":null, \"uca1400_nopad_as_cs\":null, \"uca1400_icelandic_ai_ci\":null, \"uca1400_icelandic_ai_cs\":null, \"uca1400_icelandic_as_ci\":null, \"uca1400_icelandic_as_cs\":null, \"uca1400_icelandic_nopad_ai_ci\":null, \"uca1400_icelandic_nopad_ai_cs\":null, \"uca1400_icelandic_nopad_as_ci\":null, \"uca1400_icelandic_nopad_as_cs\":null, \"uca1400_latvian_ai_ci\":null, \"uca1400_latvian_ai_cs\":null, \"uca1400_latvian_as_ci\":null, \"uca1400_latvian_as_cs\":null, \"uca1400_latvian_nopad_ai_ci\":null, \"uca1400_latvian_nopad_ai_cs\":null, \"uca1400_latvian_nopad_as_ci\":null, \"uca1400_latvian_nopad_as_cs\":null, \"uca1400_romanian_ai_ci\":null, \"uca1400_romanian_ai_cs\":null, \"uca1400_romanian_as_ci\":null, \"uca1400_romanian_as_cs\":null, \"uca1400_romanian_nopad_ai_ci\":null, \"uca1400_romanian_nopad_ai_cs\":null, \"uca1400_romanian_nopad_as_ci\":null, \"uca1400_romanian_nopad_as_cs\":null, \"uca1400_slovenian_ai_ci\":null, \"uca1400_slovenian_ai_cs\":null, \"uca1400_slovenian_as_ci\":null, \"uca1400_slovenian_as_cs\":null, \"uca1400_slovenian_nopad_ai_ci\":null, \"uca1400_slovenian_nopad_ai_cs\":null, \"uca1400_slovenian_nopad_as_ci\":null, \"uca1400_slovenian_nopad_as_cs\":null, \"uca1400_polish_ai_ci\":null, \"uca1400_polish_ai_cs\":null, \"uca1400_polish_as_ci\":null, \"uca1400_polish_as_cs\":null, \"uca1400_polish_nopad_ai_ci\":null, \"uca1400_polish_nopad_ai_cs\":null, \"uca1400_polish_nopad_as_ci\":null, \"uca1400_polish_nopad_as_cs\":null, \"uca1400_estonian_ai_ci\":null, \"uca1400_estonian_ai_cs\":null, \"uca1400_estonian_as_ci\":null, \"uca1400_estonian_as_cs\":null, \"uca1400_estonian_nopad_ai_ci\":null, \"uca1400_estonian_nopad_ai_cs\":null, \"uca1400_estonian_nopad_as_ci\":null, \"uca1400_estonian_nopad_as_cs\":null, \"uca1400_spanish_ai_ci\":null, \"uca1400_spanish_ai_cs\":null, \"uca1400_spanish_as_ci\":null, \"uca1400_spanish_as_cs\":null, \"uca1400_spanish_nopad_ai_ci\":null, \"uca1400_spanish_nopad_ai_cs\":null, \"uca1400_spanish_nopad_as_ci\":null, \"uca1400_spanish_nopad_as_cs\":null, \"uca1400_swedish_ai_ci\":null, \"uca1400_swedish_ai_cs\":null, \"uca1400_swedish_as_ci\":null, \"uca1400_swedish_as_cs\":null, \"uca1400_swedish_nopad_ai_ci\":null, \"uca1400_swedish_nopad_ai_cs\":null, \"uca1400_swedish_nopad_as_ci\":null, \"uca1400_swedish_nopad_as_cs\":null, \"uca1400_turkish_ai_ci\":null, \"uca1400_turkish_ai_cs\":null, \"uca1400_turkish_as_ci\":null, \"uca1400_turkish_as_cs\":null, \"uca1400_turkish_nopad_ai_ci\":null, \"uca1400_turkish_nopad_ai_cs\":null, \"uca1400_turkish_nopad_as_ci\":null, \"uca1400_turkish_nopad_as_cs\":null, \"uca1400_czech_ai_ci\":null, \"uca1400_czech_ai_cs\":null, \"uca1400_czech_as_ci\":null, \"uca1400_czech_as_cs\":null, \"uca1400_czech_nopad_ai_ci\":null, \"uca1400_czech_nopad_ai_cs\":null, \"uca1400_czech_nopad_as_ci\":null, \"uca1400_czech_nopad_as_cs\":null, \"uca1400_danish_ai_ci\":null, \"uca1400_danish_ai_cs\":null, \"uca1400_danish_as_ci\":null, \"uca1400_danish_as_cs\":null, \"uca1400_danish_nopad_ai_ci\":null, \"uca1400_danish_nopad_ai_cs\":null, \"uca1400_danish_nopad_as_ci\":null, \"uca1400_danish_nopad_as_cs\":null, \"uca1400_lithuanian_ai_ci\":null, \"uca1400_lithuanian_ai_cs\":null, \"uca1400_lithuanian_as_ci\":null, \"uca1400_lithuanian_as_cs\":null, \"uca1400_lithuanian_nopad_ai_ci\":null, \"uca1400_lithuanian_nopad_ai_cs\":null, \"uca1400_lithuanian_nopad_as_ci\":null, \"uca1400_lithuanian_nopad_as_cs\":null, \"uca1400_slovak_ai_ci\":null, \"uca1400_slovak_ai_cs\":null, \"uca1400_slovak_as_ci\":null, \"uca1400_slovak_as_cs\":null, \"uca1400_slovak_nopad_ai_ci\":null, \"uca1400_slovak_nopad_ai_cs\":null, \"uca1400_slovak_nopad_as_ci\":null, \"uca1400_slovak_nopad_as_cs\":null, \"uca1400_spanish2_ai_ci\":null, \"uca1400_spanish2_ai_cs\":null, \"uca1400_spanish2_as_ci\":null, \"uca1400_spanish2_as_cs\":null, \"uca1400_spanish2_nopad_ai_ci\":null, \"uca1400_spanish2_nopad_ai_cs\":null, \"uca1400_spanish2_nopad_as_ci\":null, \"uca1400_spanish2_nopad_as_cs\":null, \"uca1400_roman_ai_ci\":null, \"uca1400_roman_ai_cs\":null, \"uca1400_roman_as_ci\":null, \"uca1400_roman_as_cs\":null, \"uca1400_roman_nopad_ai_ci\":null, \"uca1400_roman_nopad_ai_cs\":null, \"uca1400_roman_nopad_as_ci\":null, \"uca1400_roman_nopad_as_cs\":null, \"uca1400_persian_ai_ci\":null, \"uca1400_persian_ai_cs\":null, \"uca1400_persian_as_ci\":null, \"uca1400_persian_as_cs\":null, \"uca1400_persian_nopad_ai_ci\":null, \"uca1400_persian_nopad_ai_cs\":null, \"uca1400_persian_nopad_as_ci\":null, \"uca1400_persian_nopad_as_cs\":null, \"uca1400_esperanto_ai_ci\":null, \"uca1400_esperanto_ai_cs\":null, \"uca1400_esperanto_as_ci\":null, \"uca1400_esperanto_as_cs\":null, \"uca1400_esperanto_nopad_ai_ci\":null, \"uca1400_esperanto_nopad_ai_cs\":null, \"uca1400_esperanto_nopad_as_ci\":null, \"uca1400_esperanto_nopad_as_cs\":null, \"uca1400_hungarian_ai_ci\":null, \"uca1400_hungarian_ai_cs\":null, \"uca1400_hungarian_as_ci\":null, \"uca1400_hungarian_as_cs\":null, \"uca1400_hungarian_nopad_ai_ci\":null, \"uca1400_hungarian_nopad_ai_cs\":null, \"uca1400_hungarian_nopad_as_ci\":null, \"uca1400_hungarian_nopad_as_cs\":null, \"uca1400_sinhala_ai_ci\":null, \"uca1400_sinhala_ai_cs\":null, \"uca1400_sinhala_as_ci\":null, \"uca1400_sinhala_as_cs\":null, \"uca1400_sinhala_nopad_ai_ci\":null, \"uca1400_sinhala_nopad_ai_cs\":null, \"uca1400_sinhala_nopad_as_ci\":null, \"uca1400_sinhala_nopad_as_cs\":null, \"uca1400_german2_ai_ci\":null, \"uca1400_german2_ai_cs\":null, \"uca1400_german2_as_ci\":null, \"uca1400_german2_as_cs\":null, \"uca1400_german2_nopad_ai_ci\":null, \"uca1400_german2_nopad_ai_cs\":null, \"uca1400_german2_nopad_as_ci\":null, \"uca1400_german2_nopad_as_cs\":null, \"uca1400_vietnamese_ai_ci\":null, \"uca1400_vietnamese_ai_cs\":null, \"uca1400_vietnamese_as_ci\":null, \"uca1400_vietnamese_as_cs\":null, \"uca1400_vietnamese_nopad_ai_ci\":null, \"uca1400_vietnamese_nopad_ai_cs\":null, \"uca1400_vietnamese_nopad_as_ci\":null, \"uca1400_vietnamese_nopad_as_cs\":null, \"uca1400_croatian_ai_ci\":null, \"uca1400_croatian_ai_cs\":null, \"uca1400_croatian_as_ci\":null, \"uca1400_croatian_as_cs\":null, \"uca1400_croatian_nopad_ai_ci\":null, \"uca1400_croatian_nopad_ai_cs\":null, \"uca1400_croatian_nopad_as_ci\":null, \"uca1400_croatian_nopad_as_cs\":null, \"cp1251_bulgarian_ci\":\"cp1251\", \"cp1251_ukrainian_ci\":\"cp1251\", \"cp1251_bin\":\"cp1251\", \"cp1251_general_ci\":\"cp1251\", \"cp1251_general_cs\":\"cp1251\", \"cp1251_nopad_bin\":\"cp1251\", \"cp1251_general_nopad_ci\":\"cp1251\", \"utf16_general_ci\":\"utf16\", \"utf16_bin\":\"utf16\", \"utf16_unicode_ci\":\"utf16\", \"utf16_icelandic_ci\":\"utf16\", \"utf16_latvian_ci\":\"utf16\", \"utf16_romanian_ci\":\"utf16\", \"utf16_slovenian_ci\":\"utf16\", \"utf16_polish_ci\":\"utf16\", \"utf16_estonian_ci\":\"utf16\", \"utf16_spanish_ci\":\"utf16\", \"utf16_swedish_ci\":\"utf16\", \"utf16_turkish_ci\":\"utf16\", \"utf16_czech_ci\":\"utf16\", \"utf16_danish_ci\":\"utf16\", \"utf16_lithuanian_ci\":\"utf16\", \"utf16_slovak_ci\":\"utf16\", \"utf16_spanish2_ci\":\"utf16\", \"utf16_roman_ci\":\"utf16\", \"utf16_persian_ci\":\"utf16\", \"utf16_esperanto_ci\":\"utf16\", \"utf16_hungarian_ci\":\"utf16\", \"utf16_sinhala_ci\":\"utf16\", \"utf16_german2_ci\":\"utf16\", \"utf16_croatian_mysql561_ci\":\"utf16\", \"utf16_unicode_520_ci\":\"utf16\", \"utf16_vietnamese_ci\":\"utf16\", \"utf16_croatian_ci\":\"utf16\", \"utf16_myanmar_ci\":\"utf16\", \"utf16_thai_520_w2\":\"utf16\", \"utf16_general_nopad_ci\":\"utf16\", \"utf16_nopad_bin\":\"utf16\", \"utf16_unicode_nopad_ci\":\"utf16\", \"utf16_unicode_520_nopad_ci\":\"utf16\", \"utf16le_general_ci\":\"utf16le\", \"utf16le_bin\":\"utf16le\", \"utf16le_general_nopad_ci\":\"utf16le\", \"utf16le_nopad_bin\":\"utf16le\", \"cp1256_general_ci\":\"cp1256\", \"cp1256_bin\":\"cp1256\", \"cp1256_general_nopad_ci\":\"cp1256\", \"cp1256_nopad_bin\":\"cp1256\", \"cp1257_lithuanian_ci\":\"cp1257\", \"cp1257_bin\":\"cp1257\", \"cp1257_general_ci\":\"cp1257\", \"cp1257_nopad_bin\":\"cp1257\", \"cp1257_general_nopad_ci\":\"cp1257\", \"utf32_general_ci\":\"utf32\", \"utf32_bin\":\"utf32\", \"utf32_unicode_ci\":\"utf32\", \"utf32_icelandic_ci\":\"utf32\", \"utf32_latvian_ci\":\"utf32\", \"utf32_romanian_ci\":\"utf32\", \"utf32_slovenian_ci\":\"utf32\", \"utf32_polish_ci\":\"utf32\", \"utf32_estonian_ci\":\"utf32\", \"utf32_spanish_ci\":\"utf32\", \"utf32_swedish_ci\":\"utf32\", \"utf32_turkish_ci\":\"utf32\", \"utf32_czech_ci\":\"utf32\", \"utf32_danish_ci\":\"utf32\", \"utf32_lithuanian_ci\":\"utf32\", \"utf32_slovak_ci\":\"utf32\", \"utf32_spanish2_ci\":\"utf32\", \"utf32_roman_ci\":\"utf32\", \"utf32_persian_ci\":\"utf32\", \"utf32_esperanto_ci\":\"utf32\", \"utf32_hungarian_ci\":\"utf32\", \"utf32_sinhala_ci\":\"utf32\", \"utf32_german2_ci\":\"utf32\", \"utf32_croatian_mysql561_ci\":\"utf32\", \"utf32_unicode_520_ci\":\"utf32\", \"utf32_vietnamese_ci\":\"utf32\", \"utf32_croatian_ci\":\"utf32\", \"utf32_myanmar_ci\":\"utf32\", \"utf32_thai_520_w2\":\"utf32\", \"utf32_general_nopad_ci\":\"utf32\", \"utf32_nopad_bin\":\"utf32\", \"utf32_unicode_nopad_ci\":\"utf32\", \"utf32_unicode_520_nopad_ci\":\"utf32\", \"binary\":\"binary\", \"geostd8_general_ci\":\"geostd8\", \"geostd8_bin\":\"geostd8\", \"geostd8_general_nopad_ci\":\"geostd8\", \"geostd8_nopad_bin\":\"geostd8\", \"cp932_japanese_ci\":\"cp932\", \"cp932_bin\":\"cp932\", \"cp932_japanese_nopad_ci\":\"cp932\", \"cp932_nopad_bin\":\"cp932\", \"eucjpms_japanese_ci\":\"eucjpms\", \"eucjpms_bin\":\"eucjpms\", \"eucjpms_japanese_nopad_ci\":\"eucjpms\", \"eucjpms_nopad_bin\":\"eucjpms\"}"
  },
  {
    "path": "sql/mysql/internal/mysqlversion/mysqlversion.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage mysqlversion\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"embed\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"golang.org/x/mod/semver\"\n)\n\n// V provides information about MySQL versions.\ntype V string\n\n// SupportsCheck reports if the version supports the CHECK\n// clause, and return the querying for getting them.\nfunc (v V) SupportsCheck() bool {\n\tu := \"8.0.16\"\n\tif v.Maria() {\n\t\tu = \"10.2.1\"\n\t}\n\treturn v.GTE(u)\n}\n\n// SupportsIndexExpr reports if the version supports\n// index expressions (functional key part).\nfunc (v V) SupportsIndexExpr() bool {\n\treturn !v.Maria() && v.GTE(\"8.0.13\")\n}\n\n// SupportsDisplayWidth reports if the version supports getting\n// the display width information from the information schema.\nfunc (v V) SupportsDisplayWidth() bool {\n\t// MySQL v8.0.19 dropped the display width\n\t// information from the information schema\n\treturn v.Maria() || v.LT(\"8.0.19\")\n}\n\n// SupportsExprDefault reports if the version supports\n// expressions in the DEFAULT clause on column definition.\nfunc (v V) SupportsExprDefault() bool {\n\tu := \"8.0.13\"\n\tif v.Maria() {\n\t\tu = \"10.2.1\"\n\t}\n\treturn v.GTE(u)\n}\n\n// SupportsEnforceCheck reports if the version supports\n// the ENFORCED option in CHECK constraint syntax.\nfunc (v V) SupportsEnforceCheck() bool {\n\treturn !v.Maria() && v.GTE(\"8.0.16\")\n}\n\n// SupportsGeneratedColumns reports if the version supports\n// the generated columns in information schema.\nfunc (v V) SupportsGeneratedColumns() bool {\n\tu := \"5.7\"\n\tif v.Maria() {\n\t\tu = \"10.2\"\n\t}\n\treturn v.GTE(u)\n}\n\n// SupportsRenameColumn reports if the version supports\n// the \"RENAME COLUMN\" clause.\nfunc (v V) SupportsRenameColumn() bool {\n\tu := \"8\"\n\tif v.Maria() {\n\t\tu = \"10.5.2\"\n\t}\n\treturn v.GTE(u)\n}\n\n// SupportsIndexComment reports if the version\n// supports comments on indexes.\nfunc (v V) SupportsIndexComment() bool {\n\t// According to Oracle release notes, comments on\n\t// indexes were added in version 5.5.3.\n\treturn v.Maria() || v.GTE(\"5.5.3\")\n}\n\n// SupportsViewUsage reports if the version supports\n// querying the VIEW_TABLE_USAGE table.\nfunc (v V) SupportsViewUsage() bool {\n\treturn !v.Maria() && v.GTE(\"8.0.13\")\n}\n\n// CharsetToCollate returns the mapping from charset to its default collation.\nfunc (v V) CharsetToCollate(conn schema.ExecQuerier) (map[string]string, error) {\n\tname := \"is/charset2collate\"\n\tif v.Maria() {\n\t\tname += \".maria\"\n\t}\n\tc2c, err := decode(name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif conn != nil {\n\t\tmayExtend(conn, \"SELECT CHARACTER_SET_NAME, DEFAULT_COLLATE_NAME FROM INFORMATION_SCHEMA.CHARACTER_SETS\", c2c)\n\t}\n\treturn c2c, nil\n}\n\n// CollateToCharset returns the mapping from a collation to its charset.\nfunc (v V) CollateToCharset(conn schema.ExecQuerier) (map[string]string, error) {\n\tname := \"is/collate2charset\"\n\tif v.Maria() {\n\t\tname += \".maria\"\n\t}\n\tc2c, err := decode(name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif conn != nil {\n\t\tmayExtend(conn, \"SELECT COLLATION_NAME, CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS\", c2c)\n\t}\n\treturn c2c, nil\n}\n\n// mayExtend the given collation/charset map from information schema.\nfunc mayExtend(conn schema.ExecQuerier, query string, to map[string]string) {\n\trows, err := conn.QueryContext(context.Background(), query)\n\tif err != nil {\n\t\treturn\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar c1, c2 sql.NullString\n\t\tif err := rows.Scan(&c1, &c2); err != nil {\n\t\t\treturn\n\t\t}\n\t\tif sqlx.ValidString(c1) && sqlx.ValidString(c2) {\n\t\t\tto[c1.String] = c2.String\n\t\t}\n\t}\n}\n\n// Maria reports if the MySQL version is MariaDB.\nfunc (v V) Maria() bool {\n\treturn strings.Index(string(v), \"MariaDB\") > 0\n}\n\n// TiDB reports if the MySQL version is TiDB.\nfunc (v V) TiDB() bool {\n\treturn strings.Index(string(v), \"TiDB\") > 0\n}\n\n// Compare returns an integer comparing two versions according to\n// semantic version precedence.\nfunc (v V) Compare(w string) int {\n\tu := string(v)\n\tswitch idx := strings.Index(u, \"-\"); {\n\tcase v.Maria():\n\t\tu = u[:strings.Index(u, \"MariaDB\")-1]\n\tcase v.TiDB():\n\t\tu = u[:strings.Index(u, \"TiDB\")-1]\n\tcase idx > 0:\n\t\t// Remove server build information, if any.\n\t\tu = u[:idx]\n\t}\n\treturn semver.Compare(\"v\"+u, \"v\"+w)\n}\n\n// GTE reports if the version is >= w.\nfunc (v V) GTE(w string) bool { return v.Compare(w) >= 0 }\n\n// LT reports if the version is < w.\nfunc (v V) LT(w string) bool { return v.Compare(w) == -1 }\n\n//go:embed is/*\nvar encoding embed.FS\n\nfunc decode(name string) (map[string]string, error) {\n\tf, err := encoding.Open(name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar m map[string]string\n\tif err := json.NewDecoder(f).Decode(&m); err != nil {\n\t\treturn nil, fmt.Errorf(\"decode %q\", name)\n\t}\n\treturn m, nil\n}\n"
  },
  {
    "path": "sql/mysql/internal/mysqlversion/mysqlversion_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage mysqlversion_test\n\nimport (\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/mysql/internal/mysqlversion\"\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestV_SupportsGeneratedColumns(t *testing.T) {\n\ttests := []struct {\n\t\tv    string\n\t\twant bool\n\t}{\n\t\t{\"5.6\", false},\n\t\t{\"5.7\", true},\n\t\t{\"5.7.0\", true},\n\t\t{\"5.7.40-0ubuntu0.18.04.1\", true},\n\t\t{\"8.0.0\", true},\n\t\t{\"10.1.1-MariaDB\", false},\n\t\t{\"10.2.1-MariaDB-10.2.1+maria~bionic\", true},\n\t\t{\"10.3.1-MariaDB-10.2.1+maria~bionic-log\", true},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.v, func(t *testing.T) {\n\t\t\tif got := mysqlversion.V(tt.v).SupportsGeneratedColumns(); got != tt.want {\n\t\t\t\tt.Errorf(\"V.SupportsGeneratedColumns() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestV_CollateToCharset(t *testing.T) {\n\tc2c, err := mysqlversion.V(\"8.0.0\").CollateToCharset(nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"utf8mb4\", c2c[\"utf8mb4_general_ci\"])\n\trequire.Empty(t, c2c[\"custom\"])\n\n\tdb, mk, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmk.ExpectQuery(\"SELECT COLLATION_NAME, CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLLATIONS\").\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"COLLATION_NAME\", \"CHARACTER_SET_NAME\"}).AddRow(\"custom\", \"unknown\"))\n\tc2c, err = mysqlversion.V(\"8.0.0\").CollateToCharset(db)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"unknown\", c2c[\"custom\"])\n}\n"
  },
  {
    "path": "sql/mysql/migrate_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysql\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\nvar (\n\tnoConn = &conn{ExecQuerier: sqlx.NoRows, V: \"8.0.31\"}\n\t// DefaultPlan provides basic planning capabilities for MySQL dialects.\n\t// Note, it is recommended to call Open, create a new Driver and use its\n\t// migrate.PlanApplier when a database connection is available.\n\tDefaultPlan migrate.PlanApplier = &planApply{conn: noConn}\n)\n\n// A planApply provides migration capabilities for schema elements.\ntype planApply struct{ *conn }\n\n// PlanChanges returns a migration plan for the given schema changes.\nfunc (p *planApply) PlanChanges(ctx context.Context, name string, changes []schema.Change, opts ...migrate.PlanOption) (*migrate.Plan, error) {\n\ts := &state{\n\t\tconn: p.conn,\n\t\tPlan: migrate.Plan{\n\t\t\tName: name,\n\t\t\t// All statements generated by state will cause implicit commit.\n\t\t\t// https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html\n\t\t\tTransactional: false,\n\t\t},\n\t}\n\tfor _, o := range opts {\n\t\to(&s.PlanOptions)\n\t}\n\tif err := verifyChanges(ctx, changes); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := s.plan(changes); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := sqlx.SetReversible(&s.Plan); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &s.Plan, nil\n}\n\n// ApplyChanges applies the changes on the database. An error is returned\n// if the driver is unable to produce a plan to it, or one of the statements\n// is failed or unsupported.\nfunc (p *planApply) ApplyChanges(ctx context.Context, changes []schema.Change, opts ...migrate.PlanOption) error {\n\treturn sqlx.ApplyChanges(ctx, changes, p, opts...)\n}\n\n// state represents the state of a planning. It is not part of\n// planApply so that multiple planning/applying can be called\n// in parallel.\ntype state struct {\n\t*conn\n\tmigrate.Plan\n\tmigrate.PlanOptions\n}\n\n// plan builds the migration plan for applying the\n// given changes on the attached connection.\nfunc (s *state) plan(changes []schema.Change) error {\n\tif s.SchemaQualifier != nil {\n\t\tif err := sqlx.CheckChangesScope(s.PlanOptions, changes); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tplanned, err := s.topLevel(changes)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif s.PlanOptions.Mode != migrate.PlanModeUnsortedDump {\n\t\tplanned, err = sqlx.DetachCycles(planned)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tplanned = sqlx.SortChanges(planned, nil)\n\t}\n\tfor _, c := range planned {\n\t\tswitch c := c.(type) {\n\t\tcase *schema.AddTable:\n\t\t\terr = s.addTable(c)\n\t\tcase *schema.DropTable:\n\t\t\terr = s.dropTable(c)\n\t\tcase *schema.ModifyTable:\n\t\t\terr = s.modifyTable(c)\n\t\tcase *schema.RenameTable:\n\t\t\ts.renameTable(c)\n\t\tdefault:\n\t\t\terr = fmt.Errorf(\"unsupported change %T\", c)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// topLevel appends first the changes for creating or dropping schemas (top-level schema elements).\nfunc (s *state) topLevel(changes []schema.Change) ([]schema.Change, error) {\n\tplanned := make([]schema.Change, 0, len(changes))\n\tfor _, c := range changes {\n\t\tswitch c := c.(type) {\n\t\tcase *schema.AddSchema:\n\t\t\tb := s.Build(\"CREATE DATABASE\")\n\t\t\tif sqlx.Has(c.Extra, &schema.IfNotExists{}) {\n\t\t\t\tb.P(\"IF NOT EXISTS\")\n\t\t\t}\n\t\t\tb.Ident(c.S.Name)\n\t\t\t// Schema was created with CHARSET, and it is not the default database character set.\n\t\t\tif a := (schema.Charset{}); sqlx.Has(c.S.Attrs, &a) && a.V != \"\" && a.V != s.charset {\n\t\t\t\tb.P(\"CHARSET\", a.V)\n\t\t\t}\n\t\t\t// Schema was created with COLLATE, and it is not the default database collation.\n\t\t\tif a := (schema.Collation{}); sqlx.Has(c.S.Attrs, &a) && a.V != \"\" && a.V != s.collate {\n\t\t\t\tb.P(\"COLLATE\", a.V)\n\t\t\t}\n\t\t\ts.append(&migrate.Change{\n\t\t\t\tCmd:     b.String(),\n\t\t\t\tSource:  c,\n\t\t\t\tReverse: s.Build(\"DROP DATABASE\").Ident(c.S.Name).String(),\n\t\t\t\tComment: fmt.Sprintf(\"add new schema named %q\", c.S.Name),\n\t\t\t})\n\t\tcase *schema.DropSchema:\n\t\t\tb := s.Build(\"DROP DATABASE\")\n\t\t\tif sqlx.Has(c.Extra, &schema.IfExists{}) {\n\t\t\t\tb.P(\"IF EXISTS\")\n\t\t\t}\n\t\t\tb.Ident(c.S.Name)\n\t\t\ts.append(&migrate.Change{\n\t\t\t\tCmd:     b.String(),\n\t\t\t\tSource:  c,\n\t\t\t\tComment: fmt.Sprintf(\"drop schema named %q\", c.S.Name),\n\t\t\t})\n\t\tcase *schema.ModifySchema:\n\t\t\tif err := s.modifySchema(c); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tdefault:\n\t\t\tplanned = append(planned, c)\n\t\t}\n\t}\n\treturn planned, nil\n}\n\n// modifySchema builds and appends the migrate.Changes for bringing\n// the schema into its modified state.\nfunc (s *state) modifySchema(modify *schema.ModifySchema) error {\n\tb, r := s.Build(), s.Build()\n\tfor _, change := range modify.Changes {\n\t\tswitch change := change.(type) {\n\t\t// Add schema attributes to an existing schema only if\n\t\t// it is different from the default server configuration.\n\t\tcase *schema.AddAttr:\n\t\t\tswitch a := change.A.(type) {\n\t\t\tcase *schema.Charset:\n\t\t\t\tif a.V != \"\" && a.V != s.charset {\n\t\t\t\t\tb.P(\"CHARSET\", a.V)\n\t\t\t\t\tr.P(\"CHARSET\", s.charset)\n\t\t\t\t}\n\t\t\tcase *schema.Collation:\n\t\t\t\tif a.V != \"\" && a.V != s.collate {\n\t\t\t\t\tb.P(\"COLLATE\", a.V)\n\t\t\t\t\tr.P(\"COLLATE\", s.collate)\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unexpected schema AddAttr: %T\", a)\n\t\t\t}\n\t\tcase *schema.ModifyAttr:\n\t\t\tswitch to := change.To.(type) {\n\t\t\tcase *schema.Charset:\n\t\t\t\tfrom, ok := change.From.(*schema.Charset)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"mismatch ModifyAttr attributes: %T != %T\", change.To, change.From)\n\t\t\t\t}\n\t\t\t\tb.P(\"CHARSET\", to.V)\n\t\t\t\tr.P(\"CHARSET\", from.V)\n\t\t\tcase *schema.Collation:\n\t\t\t\tfrom, ok := change.From.(*schema.Collation)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"mismatch ModifyAttr attributes: %T != %T\", change.To, change.From)\n\t\t\t\t}\n\t\t\t\tb.P(\"COLLATE\", to.V)\n\t\t\t\tr.P(\"COLLATE\", from.V)\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unexpected schema ModifyAttr: %T\", change)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unsupported ModifySchema change %T\", change)\n\t\t}\n\t}\n\tif b.Len() > 0 {\n\t\tbs := s.Build(\"ALTER DATABASE\").Ident(modify.S.Name)\n\t\trs := bs.Clone()\n\t\tbs.WriteString(b.String())\n\t\trs.WriteString(r.String())\n\t\ts.append(&migrate.Change{\n\t\t\tCmd:     bs.String(),\n\t\t\tReverse: rs.String(),\n\t\t\tSource:  modify,\n\t\t\tComment: fmt.Sprintf(\"modify %q schema\", modify.S.Name),\n\t\t})\n\t}\n\treturn nil\n}\n\n// addTable builds and appends a migration change\n// for creating a table in a schema.\nfunc (s *state) addTable(add *schema.AddTable) error {\n\tvar (\n\t\terrs []string\n\t\tb    = s.Build(\"CREATE TABLE\")\n\t)\n\tif sqlx.Has(add.Extra, &schema.IfNotExists{}) {\n\t\tb.P(\"IF NOT EXISTS\")\n\t}\n\tb.Table(add.T)\n\tif len(add.T.Columns) == 0 {\n\t\treturn fmt.Errorf(\"table %q has no columns\", add.T.Name)\n\t}\n\tb.WrapIndent(func(b *sqlx.Builder) {\n\t\tb.MapIndent(add.T.Columns, func(i int, b *sqlx.Builder) {\n\t\t\tif err := s.column(b, add.T, add.T.Columns[i]); err != nil {\n\t\t\t\terrs = append(errs, err.Error())\n\t\t\t}\n\t\t})\n\t\tif pk := add.T.PrimaryKey; pk != nil {\n\t\t\tb.Comma().NL().P(\"PRIMARY KEY\")\n\t\t\tindexTypeParts(b, pk)\n\t\t}\n\t\tif len(add.T.Indexes) > 0 {\n\t\t\tb.Comma()\n\t\t}\n\t\tb.MapIndent(add.T.Indexes, func(i int, b *sqlx.Builder) {\n\t\t\tidx := add.T.Indexes[i]\n\t\t\tindex(b, idx)\n\t\t})\n\t\tif len(add.T.ForeignKeys) > 0 {\n\t\t\tb.Comma()\n\t\t\tif err := s.fks(b.MapIndentErr, add.T.ForeignKeys...); err != nil {\n\t\t\t\terrs = append(errs, err.Error())\n\t\t\t}\n\t\t}\n\t\tfor _, attr := range add.T.Attrs {\n\t\t\tif c, ok := attr.(*schema.Check); ok {\n\t\t\t\tb.Comma().NL()\n\t\t\t\ts.check(b, c)\n\t\t\t}\n\t\t}\n\t})\n\tif len(errs) > 0 {\n\t\treturn fmt.Errorf(\"create table %q: %s\", add.T.Name, strings.Join(errs, \", \"))\n\t}\n\ts.tableAttrs(b, add, add.T.Attrs...)\n\ts.append(&migrate.Change{\n\t\tCmd:     b.String(),\n\t\tSource:  add,\n\t\tReverse: s.Build(\"DROP TABLE\").Table(add.T).String(),\n\t\tComment: fmt.Sprintf(\"create %q table\", add.T.Name),\n\t})\n\treturn nil\n}\n\n// dropTable builds and appends the migrate.Change\n// for dropping a table from a schema.\nfunc (s *state) dropTable(drop *schema.DropTable) error {\n\trs := &state{conn: s.conn, PlanOptions: s.PlanOptions}\n\tif err := rs.addTable(&schema.AddTable{T: drop.T}); err != nil {\n\t\treturn fmt.Errorf(\"calculate reverse for drop table %q: %w\", drop.T.Name, err)\n\t}\n\tb := s.Build(\"DROP TABLE\")\n\tif sqlx.Has(drop.Extra, &schema.IfExists{}) {\n\t\tb.P(\"IF EXISTS\")\n\t}\n\tb.Table(drop.T)\n\ts.append(&migrate.Change{\n\t\tCmd:     b.String(),\n\t\tSource:  drop,\n\t\tReverse: rs.Changes[0].Cmd,\n\t\tComment: fmt.Sprintf(\"drop %q table\", drop.T.Name),\n\t})\n\treturn nil\n}\n\n// modifyTable builds and appends the migration changes for\n// bringing the table into its modified state.\nfunc (s *state) modifyTable(modify *schema.ModifyTable) error {\n\tvar changes [2][]schema.Change\n\tif len(modify.T.Columns) == 0 {\n\t\treturn fmt.Errorf(\"table %q has no columns; drop the table instead\", modify.T.Name)\n\t}\n\tfor _, change := range skipAutoChanges(modify.Changes) {\n\t\tswitch change := change.(type) {\n\t\t// Foreign-key modification is translated into 2 steps.\n\t\t// Dropping the current foreign key and creating a new one.\n\t\tcase *schema.ModifyForeignKey:\n\t\t\t// DROP and ADD of the same constraint cannot be mixed\n\t\t\t// on the ALTER TABLE command.\n\t\t\tchanges[0] = append(changes[0], &schema.DropForeignKey{\n\t\t\t\tF: change.From,\n\t\t\t})\n\t\t\t// Drop the auto-created index for referenced if the reference was changed.\n\t\t\tif change.Change.Is(schema.ChangeRefTable | schema.ChangeRefColumn) {\n\t\t\t\tchanges[0] = append(changes[0], &schema.DropIndex{\n\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\tName:  change.From.Symbol,\n\t\t\t\t\t\tTable: modify.T,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t\tchanges[1] = append(changes[1], &schema.AddForeignKey{\n\t\t\t\tF: change.To,\n\t\t\t})\n\t\t// Index modification requires rebuilding the index.\n\t\tcase *schema.ModifyIndex:\n\t\t\tchanges[0] = append(changes[0], &schema.DropIndex{\n\t\t\t\tI: change.From,\n\t\t\t})\n\t\t\tchanges[1] = append(changes[1], &schema.AddIndex{\n\t\t\t\tI: change.To,\n\t\t\t})\n\t\tdefault:\n\t\t\tchanges[1] = append(changes[1], change)\n\t\t}\n\t}\n\tfor i := range changes {\n\t\tif len(changes[i]) > 0 {\n\t\t\tif err := s.alterTable(modify.T, changes[i]); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// alterTable modifies the given table by executing on it a list of\n// changes in one SQL statement.\nfunc (s *state) alterTable(t *schema.Table, changes []schema.Change) error {\n\tvar (\n\t\treverse    []schema.Change\n\t\tname       = t.Name\n\t\treversible = true\n\t)\n\tbuild := func(changes []schema.Change) (string, error) {\n\t\tb := s.Build(\"ALTER TABLE\").SchemaResource(t.Schema, name)\n\t\terr := b.MapCommaErr(changes, func(i int, b *sqlx.Builder) error {\n\t\t\tswitch change := changes[i].(type) {\n\t\t\tcase *schema.RenameTable:\n\t\t\t\tb.P(\"RENAME TO\").Table(change.To)\n\t\t\t\t// Next time \"build\" is called, it\n\t\t\t\t// will refer to the new table name.\n\t\t\t\tname = change.To.Name\n\t\t\t\treverse = append(reverse, &schema.RenameTable{From: change.To, To: change.From})\n\t\t\tcase *schema.AddColumn:\n\t\t\t\tb.P(\"ADD COLUMN\")\n\t\t\t\tif err := s.column(b, t, change.C); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.DropColumn{C: change.C})\n\t\t\tcase *schema.ModifyColumn:\n\t\t\t\tif err := checkChangeGenerated(change.From, change.To); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\t// In case the column was both modified and renamed.\n\t\t\t\tif change.To.Name != change.From.Name {\n\t\t\t\t\tb.P(\"CHANGE COLUMN\").Ident(change.From.Name)\n\t\t\t\t} else {\n\t\t\t\t\tb.P(\"MODIFY COLUMN\")\n\t\t\t\t}\n\t\t\t\tif err := s.column(b, t, change.To); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.ModifyColumn{\n\t\t\t\t\tFrom:   change.To,\n\t\t\t\t\tTo:     change.From,\n\t\t\t\t\tChange: change.Change,\n\t\t\t\t})\n\t\t\tcase *schema.RenameColumn:\n\t\t\t\tif s.SupportsRenameColumn() {\n\t\t\t\t\tb.P(\"RENAME COLUMN\").Ident(change.From.Name).P(\"TO\").Ident(change.To.Name)\n\t\t\t\t} else {\n\t\t\t\t\tb.P(\"CHANGE COLUMN\").Ident(change.From.Name)\n\t\t\t\t\tif err := s.column(b, t, change.To); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.RenameColumn{From: change.To, To: change.From})\n\t\t\tcase *schema.DropColumn:\n\t\t\t\tb.P(\"DROP COLUMN\").Ident(change.C.Name)\n\t\t\t\treverse = append(reverse, &schema.AddColumn{C: change.C})\n\t\t\tcase *schema.AddIndex:\n\t\t\t\tb.P(\"ADD\")\n\t\t\t\tindex(b, change.I)\n\t\t\t\treverse = append(reverse, &schema.DropIndex{I: change.I})\n\t\t\tcase *schema.RenameIndex:\n\t\t\t\tb.P(\"RENAME INDEX\").Ident(change.From.Name).P(\"TO\").Ident(change.To.Name)\n\t\t\t\treverse = append(reverse, &schema.RenameIndex{From: change.To, To: change.From})\n\t\t\tcase *schema.DropIndex:\n\t\t\t\tb.P(\"DROP INDEX\").Ident(change.I.Name)\n\t\t\t\treverse = append(reverse, &schema.AddIndex{I: change.I})\n\t\t\tcase *schema.AddPrimaryKey:\n\t\t\t\tb.P(\"ADD PRIMARY KEY\")\n\t\t\t\tindexTypeParts(b, change.P)\n\t\t\t\treverse = append(reverse, &schema.DropPrimaryKey{P: change.P})\n\t\t\tcase *schema.DropPrimaryKey:\n\t\t\t\tb.P(\"DROP PRIMARY KEY\")\n\t\t\t\treverse = append(reverse, &schema.AddPrimaryKey{P: change.P})\n\t\t\tcase *schema.ModifyPrimaryKey:\n\t\t\t\tb.P(\"DROP PRIMARY KEY, ADD PRIMARY KEY\")\n\t\t\t\tindexTypeParts(b, change.To)\n\t\t\t\treverse = append(reverse, &schema.ModifyPrimaryKey{From: change.To, To: change.From, Change: change.Change})\n\t\t\tcase *schema.AddForeignKey:\n\t\t\t\tb.P(\"ADD\")\n\t\t\t\tif err := s.fks(b.MapCommaErr, change.F); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.DropForeignKey{F: change.F})\n\t\t\tcase *schema.DropForeignKey:\n\t\t\t\tb.P(\"DROP FOREIGN KEY\").Ident(change.F.Symbol)\n\t\t\t\treverse = append(reverse, &schema.AddForeignKey{F: change.F})\n\t\t\tcase *schema.AddAttr:\n\t\t\t\ts.tableAttrs(b, change, change.A)\n\t\t\tcase *schema.DropAttr:\n\t\t\t\ts.tableAttrs(b, change, change.A)\n\t\t\tcase *schema.ModifyAttr:\n\t\t\t\ts.tableAttrs(b, change, change.To)\n\t\t\t\treverse = append(reverse, &schema.ModifyAttr{\n\t\t\t\t\tFrom: change.To,\n\t\t\t\t\tTo:   change.From,\n\t\t\t\t})\n\t\t\tcase *schema.AddCheck:\n\t\t\t\ts.check(b.P(\"ADD\"), change.C)\n\t\t\t\t// Reverse operation is supported if\n\t\t\t\t// the constraint name is not generated.\n\t\t\t\tif reversible = reversible && change.C.Name != \"\"; reversible {\n\t\t\t\t\treverse = append(reverse, &schema.DropCheck{C: change.C})\n\t\t\t\t}\n\t\t\tcase *schema.DropCheck:\n\t\t\t\tb.P(\"DROP CONSTRAINT\").Ident(change.C.Name)\n\t\t\t\treverse = append(reverse, &schema.AddCheck{C: change.C})\n\t\t\tcase *schema.ModifyCheck:\n\t\t\t\tswitch {\n\t\t\t\tcase change.From.Name == \"\":\n\t\t\t\t\treturn errors.New(\"cannot modify unnamed check constraint\")\n\t\t\t\tcase change.From.Name != change.To.Name:\n\t\t\t\t\treturn fmt.Errorf(\"mismatch check constraint names: %q != %q\", change.From.Name, change.To.Name)\n\t\t\t\t// Enforcement added.\n\t\t\t\tcase s.SupportsEnforceCheck() && sqlx.Has(change.From.Attrs, &Enforced{}) && !sqlx.Has(change.To.Attrs, &Enforced{}):\n\t\t\t\t\tb.P(\"ALTER CHECK\").Ident(change.From.Name).P(\"ENFORCED\")\n\t\t\t\t// Enforcement dropped.\n\t\t\t\tcase s.SupportsEnforceCheck() && !sqlx.Has(change.From.Attrs, &Enforced{}) && sqlx.Has(change.To.Attrs, &Enforced{}):\n\t\t\t\t\tb.P(\"ALTER CHECK\").Ident(change.From.Name).P(\"NOT ENFORCED\")\n\t\t\t\t// Expr was changed.\n\t\t\t\tcase change.From.Expr != change.To.Expr:\n\t\t\t\t\tb.P(\"DROP CHECK\").Ident(change.From.Name).Comma().P(\"ADD\")\n\t\t\t\t\ts.check(b, change.To)\n\t\t\t\tdefault:\n\t\t\t\t\treturn errors.New(\"unknown check constraint change\")\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.ModifyCheck{\n\t\t\t\t\tFrom: change.To,\n\t\t\t\t\tTo:   change.From,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn b.String(), nil\n\t}\n\tcmd, err := build(changes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"alter table %q: %v\", t.Name, err)\n\t}\n\tchange := &migrate.Change{\n\t\tCmd: cmd,\n\t\tSource: &schema.ModifyTable{\n\t\t\tT:       t,\n\t\t\tChanges: changes,\n\t\t},\n\t\tComment: fmt.Sprintf(\"modify %q table\", t.Name),\n\t}\n\tif reversible {\n\t\t// Changes should be reverted in\n\t\t// a reversed order they were created.\n\t\tsqlx.ReverseChanges(reverse)\n\t\tif change.Reverse, err = build(reverse); err != nil {\n\t\t\treturn fmt.Errorf(\"reversed alter table %q: %v\", t.Name, err)\n\t\t}\n\t}\n\ts.append(change)\n\treturn nil\n}\n\nfunc (s *state) renameTable(c *schema.RenameTable) {\n\ts.append(&migrate.Change{\n\t\tSource:  c,\n\t\tComment: fmt.Sprintf(\"rename a table from %q to %q\", c.From.Name, c.To.Name),\n\t\tCmd:     s.Build(\"RENAME TABLE\").Table(c.From).P(\"TO\").Table(c.To).String(),\n\t\tReverse: s.Build(\"RENAME TABLE\").Table(c.To).P(\"TO\").Table(c.From).String(),\n\t})\n}\n\nfunc (s *state) column(b *sqlx.Builder, t *schema.Table, c *schema.Column) error {\n\ttyp, err := FormatType(c.Type.Type)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"format type for column %q: %w\", c.Name, err)\n\t}\n\tb.Ident(c.Name).P(typ)\n\tif cs := (schema.Charset{}); sqlx.Has(c.Attrs, &cs) {\n\t\tif !supportsCharset(c.Type.Type) {\n\t\t\treturn fmt.Errorf(\"column %q of type %T does not support the CHARSET attribute\", c.Name, c.Type.Type)\n\t\t}\n\t\t// Define the charset explicitly\n\t\t// in case it is not the default.\n\t\tif s.character(t) != cs.V {\n\t\t\tb.P(\"CHARSET\", cs.V)\n\t\t}\n\t}\n\tvar (\n\t\tx   schema.GeneratedExpr\n\t\tasX = sqlx.Has(c.Attrs, &x)\n\t)\n\tif asX {\n\t\tb.P(\"AS\", sqlx.MayWrap(x.Expr), x.Type)\n\t}\n\t// MariaDB does not accept [NOT NULL | NULL]\n\t// as part of the generated columns' syntax.\n\tif !asX || !s.Maria() {\n\t\tif !c.Type.Null {\n\t\t\tb.P(\"NOT\")\n\t\t}\n\t\tb.P(\"NULL\")\n\t}\n\ts.columnDefault(b, c)\n\t// Add manually the JSON_VALID constraint for older\n\t// versions < 10.4.3. See Driver.checks for full info.\n\tif _, ok := c.Type.Type.(*schema.JSONType); ok && s.Maria() && s.LT(\"10.4.3\") && !sqlx.Has(c.Attrs, &schema.Check{}) {\n\t\tb.P(\"CHECK\").Wrap(func(b *sqlx.Builder) {\n\t\t\tb.WriteString(fmt.Sprintf(\"json_valid(`%s`)\", c.Name))\n\t\t})\n\t}\n\tfor _, a := range c.Attrs {\n\t\tswitch a := a.(type) {\n\t\tcase *schema.Charset:\n\t\t\t// CHARSET is handled above in the \"data_type\" stage.\n\t\tcase *schema.Collation:\n\t\t\tif !supportsCharset(c.Type.Type) {\n\t\t\t\treturn fmt.Errorf(\"column %q of type %T does not support the COLLATE attribute\", c.Name, c.Type.Type)\n\t\t\t}\n\t\t\t// Define the collation explicitly\n\t\t\t// in case it is not the default.\n\t\t\tif s.collation(t) != a.V {\n\t\t\t\tb.P(\"COLLATE\", a.V)\n\t\t\t}\n\t\tcase *OnUpdate:\n\t\t\tb.P(\"ON UPDATE\", a.A)\n\t\tcase *AutoIncrement:\n\t\t\tb.P(\"AUTO_INCREMENT\")\n\t\t\t// Auto increment with value should be configured on table options.\n\t\t\tif a.V > 0 && !sqlx.Has(t.Attrs, &AutoIncrement{}) {\n\t\t\t\tt.Attrs = append(t.Attrs, a)\n\t\t\t}\n\t\tdefault:\n\t\t\ts.attr(b, a)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc index(b *sqlx.Builder, idx *schema.Index) {\n\tswitch t := indexType(idx.Attrs); {\n\tcase idx.Unique:\n\t\tb.P(\"UNIQUE\")\n\tcase t.T == IndexTypeFullText:\n\t\tif p := (&IndexParser{}); sqlx.Has(idx.Attrs, p) {\n\t\t\tdefer func() { b.P(\"WITH PARSER\").Ident(p.P) }()\n\t\t}\n\t\tb.P(t.T)\n\tcase t.T == IndexTypeSpatial:\n\t\tb.P(t.T)\n\t}\n\tb.P(\"INDEX\").Ident(idx.Name)\n\tindexTypeParts(b, idx)\n\tif c := (schema.Comment{}); sqlx.Has(idx.Attrs, &c) {\n\t\tb.P(\"COMMENT\", quote(c.Text))\n\t}\n}\n\nfunc indexTypeParts(b *sqlx.Builder, idx *schema.Index) {\n\t// Skip BTREE as it is the default type.\n\tif t := indexType(idx.Attrs); t.T == IndexTypeHash {\n\t\tb.P(\"USING\", t.T)\n\t}\n\tb.Wrap(func(b *sqlx.Builder) {\n\t\tb.MapComma(idx.Parts, func(i int, b *sqlx.Builder) {\n\t\t\tswitch part := idx.Parts[i]; {\n\t\t\tcase part.C != nil:\n\t\t\t\tb.Ident(part.C.Name)\n\t\t\tcase part.X != nil:\n\t\t\t\tb.WriteString(sqlx.MayWrap(part.X.(*schema.RawExpr).X))\n\t\t\t}\n\t\t\tif s := (&SubPart{}); sqlx.Has(idx.Parts[i].Attrs, s) {\n\t\t\t\tb.WriteString(fmt.Sprintf(\"(%d)\", s.Len))\n\t\t\t}\n\t\t\t// Ignore default collation (i.e. \"ASC\")\n\t\t\tif idx.Parts[i].Desc {\n\t\t\t\tb.P(\"DESC\")\n\t\t\t}\n\t\t})\n\t})\n}\n\nfunc (s *state) fks(commaF func(any, func(int, *sqlx.Builder) error) error, fks ...*schema.ForeignKey) error {\n\treturn commaF(fks, func(i int, b *sqlx.Builder) error {\n\t\tfk := fks[i]\n\t\tif fk.Symbol != \"\" {\n\t\t\tb.P(\"CONSTRAINT\").Ident(fk.Symbol)\n\t\t}\n\t\tb.P(\"FOREIGN KEY\")\n\t\tb.Wrap(func(b *sqlx.Builder) {\n\t\t\tb.MapComma(fk.Columns, func(i int, b *sqlx.Builder) {\n\t\t\t\tb.Ident(fk.Columns[i].Name)\n\t\t\t})\n\t\t})\n\t\tb.P(\"REFERENCES\").Table(fk.RefTable)\n\t\tb.Wrap(func(b *sqlx.Builder) {\n\t\t\tb.MapComma(fk.RefColumns, func(i int, b *sqlx.Builder) {\n\t\t\t\tb.Ident(fk.RefColumns[i].Name)\n\t\t\t})\n\t\t})\n\t\tif fk.OnUpdate != \"\" {\n\t\t\tb.P(\"ON UPDATE\", string(fk.OnUpdate))\n\t\t}\n\t\tif fk.OnDelete != \"\" {\n\t\t\tb.P(\"ON DELETE\", string(fk.OnDelete))\n\t\t}\n\t\tif fk.OnUpdate == schema.SetNull || fk.OnDelete == schema.SetNull {\n\t\t\tfor _, c := range fk.Columns {\n\t\t\t\tif !c.Type.Null {\n\t\t\t\t\treturn fmt.Errorf(\"foreign key constraint was %[1]q SET NULL, but column %[1]q is NOT NULL\", c.Name)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n}\n\n// tableAttrs writes the given table attributes to the SQL\n// statement builder when a table is created or altered.\nfunc (s *state) tableAttrs(b *sqlx.Builder, c schema.Change, attrs ...schema.Attr) {\n\tfor _, a := range attrs {\n\t\tswitch a := a.(type) {\n\t\tcase *CreateOptions:\n\t\t\tb.P(a.V)\n\t\tcase *AutoIncrement:\n\t\t\t// Update the AUTO_INCREMENT if it is a table modification, or it is not the default.\n\t\t\tif _, ok := c.(*schema.ModifyAttr); ok || a.V > 1 {\n\t\t\t\tb.P(\"AUTO_INCREMENT\", strconv.FormatInt(a.V, 10))\n\t\t\t}\n\t\tcase *Engine:\n\t\t\t// Update the ENGINE if it is a table modification, or it is not the default.\n\t\t\tif _, ok := c.(*schema.ModifyAttr); ok || !a.Default {\n\t\t\t\tb.P(\"ENGINE\", a.V)\n\t\t\t}\n\t\tcase *schema.Check:\n\t\t\t// Ignore CHECK constraints as they are not real attributes,\n\t\t\t// and handled on CREATE or ALTER.\n\t\tcase *schema.Charset:\n\t\t\tb.P(\"CHARSET\", a.V)\n\t\tcase *schema.Collation:\n\t\t\tb.P(\"COLLATE\", a.V)\n\t\tcase *schema.Comment:\n\t\t\tb.P(\"COMMENT\", quote(a.Text))\n\t\t}\n\t}\n}\n\n// character returns the table character-set from its attributes\n// or from the default defined in the schema or the database.\nfunc (s *state) character(t *schema.Table) string {\n\tvar c schema.Charset\n\tif sqlx.Has(t.Attrs, &c) || t.Schema != nil && sqlx.Has(t.Schema.Attrs, &c) {\n\t\treturn c.V\n\t}\n\treturn s.charset\n}\n\n// collation returns the table collation from its attributes\n// or from the default defined in the schema or the database.\nfunc (s *state) collation(t *schema.Table) string {\n\tvar c schema.Collation\n\tif sqlx.Has(t.Attrs, &c) || t.Schema != nil && sqlx.Has(t.Schema.Attrs, &c) {\n\t\treturn c.V\n\t}\n\treturn s.collate\n}\n\nfunc (s *state) append(c *migrate.Change) {\n\ts.Changes = append(s.Changes, c)\n}\n\nfunc (*state) attr(b *sqlx.Builder, attrs ...schema.Attr) {\n\tfor _, a := range attrs {\n\t\tswitch a := a.(type) {\n\t\tcase *schema.Collation:\n\t\t\tb.P(\"COLLATE\", a.V)\n\t\tcase *schema.Comment:\n\t\t\tb.P(\"COMMENT\", quote(a.Text))\n\t\t}\n\t}\n}\n\n// columnDefault writes the default value of column to the builder.\nfunc (s *state) columnDefault(b *sqlx.Builder, c *schema.Column) {\n\tswitch x := c.Default.(type) {\n\tcase *schema.Literal:\n\t\tv := x.V\n\t\tif !hasNumericDefault(c.Type.Type) && !isHex(v) {\n\t\t\tv = quote(v)\n\t\t}\n\t\tb.P(\"DEFAULT\", v)\n\tcase *schema.RawExpr:\n\t\tv := x.X\n\t\t// For backwards compatibility, quote raw expressions that are not wrapped\n\t\t// with parens for non-numeric column types (i.e. literals).\n\t\tswitch t := c.Type.Type; {\n\t\tcase isHex(v), hasNumericDefault(t), strings.HasPrefix(v, \"(\") && strings.HasSuffix(v, \")\"):\n\t\tdefault:\n\t\t\tif _, ok := t.(*schema.TimeType); !ok || !strings.HasPrefix(strings.ToLower(v), currentTS) {\n\t\t\t\tv = quote(v)\n\t\t\t}\n\t\t}\n\t\tb.P(\"DEFAULT\", v)\n\t}\n}\n\n// Build instantiates a new builder and writes the given phrase to it.\nfunc (s *state) Build(phrases ...string) *sqlx.Builder {\n\treturn (*Driver).StmtBuilder(nil, s.PlanOptions).\n\t\tP(phrases...)\n}\n\n// skipAutoChanges filters unnecessary changes that are automatically\n// happened by the database when ALTER TABLE is executed.\nfunc skipAutoChanges(changes []schema.Change) []schema.Change {\n\tvar (\n\t\tdropC   = make(map[string]bool)\n\t\tplanned = make([]schema.Change, 0, len(changes))\n\t)\n\tfor _, c := range changes {\n\t\tif c, ok := c.(*schema.DropColumn); ok {\n\t\t\tdropC[c.C.Name] = true\n\t\t}\n\t}\n\tfor i, c := range changes {\n\t\t// Simple case for skipping key dropping, if its columns are dropped.\n\t\t// https://dev.mysql.com/doc/refman/8.0/en/alter-table.html#alter-table-add-drop-column\n\t\tc, ok := c.(*schema.DropIndex)\n\t\tif !ok {\n\t\t\tplanned = append(planned, changes[i])\n\t\t\tcontinue\n\t\t}\n\t\tfor _, p := range c.I.Parts {\n\t\t\tif p.C == nil || !dropC[p.C.Name] {\n\t\t\t\tplanned = append(planned, c)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn planned\n}\n\n// checks writes the CHECK constraint to the builder.\nfunc (s *state) check(b *sqlx.Builder, c *schema.Check) {\n\tif c.Name != \"\" {\n\t\tb.P(\"CONSTRAINT\").Ident(c.Name)\n\t}\n\tb.P(\"CHECK\", sqlx.MayWrap(c.Expr))\n\tif s.SupportsEnforceCheck() && sqlx.Has(c.Attrs, &Enforced{}) {\n\t\tb.P(\"ENFORCED\")\n\t}\n}\n\n// supportsCharset reports if the given type supports the CHARSET and COLLATE\n// clauses. See: https://dev.mysql.com/doc/refman/8.0/en/charset-column.html\nfunc supportsCharset(t schema.Type) bool {\n\tswitch t.(type) {\n\tcase *schema.StringType, *schema.EnumType, *SetType:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// checkChangeGenerated checks if the change of a generated column is valid.\nfunc checkChangeGenerated(from, to *schema.Column) error {\n\tvar fromX, toX schema.GeneratedExpr\n\tswitch fromHas, toHas := sqlx.Has(from.Attrs, &fromX), sqlx.Has(to.Attrs, &toX); {\n\tcase !fromHas && toHas && storedOrVirtual(toX.Type) == virtual:\n\t\treturn fmt.Errorf(\"changing column %q to VIRTUAL generated column is not supported (drop and add is required)\", from.Name)\n\tcase fromHas && !toHas && storedOrVirtual(fromX.Type) == virtual:\n\t\treturn fmt.Errorf(\"changing VIRTUAL generated column %q to non-generated column is not supported (drop and add is required)\", from.Name)\n\tcase fromHas && toHas && storedOrVirtual(fromX.Type) != storedOrVirtual(toX.Type):\n\t\treturn fmt.Errorf(\"changing the store type of generated column %q from %q to %q is not supported\", from.Name, storedOrVirtual(fromX.Type), storedOrVirtual(toX.Type))\n\t}\n\treturn nil\n}\n\nfunc quote(s string) string {\n\tif sqlx.IsQuoted(s, '\"', '\\'') {\n\t\treturn s\n\t}\n\treturn strconv.Quote(s)\n}\n"
  },
  {
    "path": "sql/mysql/migrate_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysql\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/internal/sqltest\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestMigrate_ApplyChanges(t *testing.T) {\n\tmigrate, mk, err := newMigrate(\"8.0.13\")\n\trequire.NoError(t, err)\n\tmk.ExpectExec(sqltest.Escape(\"CREATE DATABASE `test` CHARSET latin\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 1))\n\tmk.ExpectExec(sqltest.Escape(\"DROP DATABASE `atlas`\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 1))\n\tmk.ExpectExec(sqltest.Escape(\"DROP TABLE `users`\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tmk.ExpectExec(sqltest.Escape(\"CREATE TABLE `users` (`id` bigint NOT NULL)\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tmk.ExpectExec(sqltest.Escape(\"DROP TABLE IF EXISTS `public`.`pets`\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tmk.ExpectExec(sqltest.Escape(\"CREATE TABLE IF NOT EXISTS `public`.`pets` (`a` int NOT NULL DEFAULT (int(rand())), `b` bigint NOT NULL DEFAULT 1, `c` bigint NULL, PRIMARY KEY (`a`, `b`), UNIQUE INDEX `b_c_unique` (`b`, `c`) COMMENT \\\"comment\\\")\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tmk.ExpectExec(sqltest.Escape(\"ALTER TABLE `users` DROP INDEX `id_spouse_id`\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tmk.ExpectExec(sqltest.Escape(\"ALTER TABLE `users` ADD CONSTRAINT `spouse` FOREIGN KEY (`spouse_id`) REFERENCES `users` (`id`) ON DELETE SET NULL, ADD INDEX `id_spouse_id` (`spouse_id`, `id` DESC) COMMENT \\\"comment\\\"\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tmk.ExpectExec(sqltest.Escape(\"CREATE TABLE `posts` (`id` bigint NOT NULL, `author_id` bigint NULL, CONSTRAINT `author` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`))\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tmk.ExpectExec(sqltest.Escape(\"CREATE TABLE `comments` (`id` bigint NOT NULL, `post_id` bigint NULL, CONSTRAINT `comment` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`))\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tns := &schema.Schema{Name: \"public\"}\n\terr = migrate.ApplyChanges(context.Background(), []schema.Change{\n\t\t&schema.AddSchema{S: &schema.Schema{Name: \"test\", Attrs: []schema.Attr{&schema.Charset{V: \"latin\"}}}},\n\t\t&schema.DropSchema{S: &schema.Schema{Name: \"atlas\", Attrs: []schema.Attr{&schema.Charset{V: \"latin\"}}}},\n\t\t&schema.DropTable{\n\t\t\tT: &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t&schema.AddTable{\n\t\t\tT: &schema.Table{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t&schema.DropTable{\n\t\t\tT: &schema.Table{\n\t\t\t\tName:   \"pets\",\n\t\t\t\tSchema: ns,\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t},\n\t\t\t},\n\t\t\tExtra: []schema.Clause{&schema.IfExists{}},\n\t\t},\n\t\t&schema.AddTable{\n\t\t\tT: func() *schema.Table {\n\t\t\t\tt := &schema.Table{\n\t\t\t\t\tName:   \"pets\",\n\t\t\t\t\tSchema: ns,\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"a\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}, Default: &schema.RawExpr{X: \"(int(rand()))\"}},\n\t\t\t\t\t\t{Name: \"b\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}, Default: &schema.Literal{V: \"1\"}},\n\t\t\t\t\t\t{Name: \"c\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tt.PrimaryKey = &schema.Index{\n\t\t\t\t\tParts: []*schema.IndexPart{{C: t.Columns[0]}, {C: t.Columns[1]}},\n\t\t\t\t}\n\t\t\t\tt.Indexes = []*schema.Index{\n\t\t\t\t\t{Name: \"b_c_unique\", Unique: true, Parts: []*schema.IndexPart{{C: t.Columns[1]}, {C: t.Columns[2]}}, Attrs: []schema.Attr{&schema.Comment{Text: \"comment\"}}},\n\t\t\t\t}\n\t\t\t\treturn t\n\t\t\t}(),\n\t\t\tExtra: []schema.Clause{\n\t\t\t\t&schema.IfNotExists{},\n\t\t\t},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\terr = migrate.ApplyChanges(context.Background(), func() []schema.Change {\n\t\tusers := &schema.Table{\n\t\t\tName: \"users\",\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t{Name: \"spouse_id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true}},\n\t\t\t},\n\t\t}\n\t\tposts := &schema.Table{\n\t\t\tName: \"posts\",\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t{Name: \"author_id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true}},\n\t\t\t},\n\t\t}\n\t\tposts.ForeignKeys = []*schema.ForeignKey{\n\t\t\t{Symbol: \"author\", Table: posts, Columns: posts.Columns[1:], RefTable: users, RefColumns: users.Columns[:1]},\n\t\t}\n\t\tcomments := &schema.Table{\n\t\t\tName: \"comments\",\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t{Name: \"post_id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true}},\n\t\t\t},\n\t\t}\n\t\tcomments.ForeignKeys = []*schema.ForeignKey{\n\t\t\t{Symbol: \"comment\", Table: comments, Columns: comments.Columns[1:], RefTable: posts, RefColumns: posts.Columns[:1]},\n\t\t}\n\t\treturn []schema.Change{\n\t\t\t&schema.AddTable{T: posts},\n\t\t\t&schema.AddTable{T: comments},\n\t\t\t&schema.ModifyTable{\n\t\t\t\tT: users,\n\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t&schema.AddForeignKey{\n\t\t\t\t\t\tF: &schema.ForeignKey{\n\t\t\t\t\t\t\tSymbol:     \"spouse\",\n\t\t\t\t\t\t\tTable:      users,\n\t\t\t\t\t\t\tColumns:    users.Columns[1:],\n\t\t\t\t\t\t\tRefTable:   users,\n\t\t\t\t\t\t\tRefColumns: users.Columns[:1],\n\t\t\t\t\t\t\tOnDelete:   \"SET NULL\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t&schema.ModifyIndex{\n\t\t\t\t\t\tFrom: &schema.Index{Name: \"id_spouse_id\", Parts: []*schema.IndexPart{{C: users.Columns[0]}, {C: users.Columns[1]}}},\n\t\t\t\t\t\tTo: &schema.Index{\n\t\t\t\t\t\t\tName: \"id_spouse_id\",\n\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t{C: users.Columns[1]},\n\t\t\t\t\t\t\t\t{C: users.Columns[0], Desc: true},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t&schema.Comment{Text: \"comment\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t}())\n\trequire.NoError(t, err)\n}\n\nfunc TestMigrate_DetachCycles(t *testing.T) {\n\tmigrate, mk, err := newMigrate(\"8.0.13\")\n\trequire.NoError(t, err)\n\tmk.ExpectExec(sqltest.Escape(\"CREATE TABLE `users` (`id` bigint NOT NULL, `workplace_id` bigint NULL)\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tmk.ExpectExec(sqltest.Escape(\"CREATE TABLE `workplaces` (`id` bigint NOT NULL, `owner_id` bigint NULL)\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tmk.ExpectExec(sqltest.Escape(\"ALTER TABLE `users` ADD CONSTRAINT `workplace` FOREIGN KEY (`workplace_id`) REFERENCES `workplaces` (`id`)\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\tmk.ExpectExec(sqltest.Escape(\"ALTER TABLE `workplaces` ADD CONSTRAINT `owner` FOREIGN KEY (`owner_id`) REFERENCES `users` (`id`)\")).\n\t\tWillReturnResult(sqlmock.NewResult(0, 0))\n\terr = migrate.ApplyChanges(context.Background(), func() []schema.Change {\n\t\tusers := &schema.Table{\n\t\t\tName: \"users\",\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t{Name: \"workplace_id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true}},\n\t\t\t},\n\t\t}\n\t\tworkplaces := &schema.Table{\n\t\t\tName: \"workplaces\",\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t{Name: \"owner_id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}, Null: true}},\n\t\t\t},\n\t\t}\n\t\tusers.ForeignKeys = []*schema.ForeignKey{\n\t\t\t{Symbol: \"workplace\", Table: users, Columns: users.Columns[1:], RefTable: workplaces, RefColumns: workplaces.Columns[:1]},\n\t\t}\n\t\tworkplaces.ForeignKeys = []*schema.ForeignKey{\n\t\t\t{Symbol: \"owner\", Table: workplaces, Columns: workplaces.Columns[1:], RefTable: users, RefColumns: users.Columns[:1]},\n\t\t}\n\t\treturn []schema.Change{\n\t\t\t&schema.AddTable{T: users},\n\t\t\t&schema.AddTable{T: workplaces},\n\t\t}\n\t}())\n\trequire.NoError(t, err)\n}\n\nfunc TestPlanChanges(t *testing.T) {\n\ttests := []struct {\n\t\tversion  string\n\t\tchanges  []schema.Change\n\t\toptions  []migrate.PlanOption\n\t\twantPlan *migrate.Plan\n\t\twantErr  bool\n\t}{\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{T: schema.NewTable(\"users\")},\n\t\t\t},\n\t\t\t// Table \"users\" has no columns.\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{T: schema.NewTable(\"users\")},\n\t\t\t},\n\t\t\t// Table \"users\" has no columns; drop the table instead.\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddSchema{S: schema.New(\"test\").SetCharset(\"utf8mb4\"), Extra: []schema.Clause{&schema.IfNotExists{}}},\n\t\t\t\t&schema.DropSchema{S: schema.New(\"test\").SetCharset(\"utf8mb4\"), Extra: []schema.Clause{&schema.IfExists{}}},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: false,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"CREATE DATABASE IF NOT EXISTS `test` CHARSET utf8mb4\",\n\t\t\t\t\t\tReverse: \"DROP DATABASE `test`\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd: \"DROP DATABASE IF EXISTS `test`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\")).\n\t\t\t\t\t\tAddAttrs(&Engine{V: EngineInnoDB, Default: true}),\n\t\t\t\t},\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: schema.NewTable(\"pets\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\")).\n\t\t\t\t\t\tAddAttrs(&Engine{V: EngineMyISAM, Default: false}),\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"CREATE TABLE `users` (`id` int NOT NULL)\",\n\t\t\t\t\t\tReverse: \"DROP TABLE `users`\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"CREATE TABLE `pets` (`id` int NOT NULL) ENGINE MyISAM\",\n\t\t\t\t\t\tReverse: \"DROP TABLE `pets`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").AddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameTable{From: schema.NewTable(\"users\"), To: schema.NewTable(\"accounts\")},\n\t\t\t\t\t}},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` RENAME TO `accounts`\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `accounts` RENAME TO `users`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").AddColumns(schema.NewIntColumn(\"id\", \"int\"), schema.NewStringColumn(\"name\", \"varchar(255)\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameTable{From: schema.NewTable(\"users\"), To: schema.NewTable(\"accounts\")},\n\t\t\t\t\t\t&schema.AddColumn{C: schema.NewStringColumn(\"name\", \"varchar(255)\")},\n\t\t\t\t\t}},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` RENAME TO `accounts`, ADD COLUMN `name` varchar(255) NOT NULL\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `accounts` DROP COLUMN `name`, RENAME TO `users`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t\tschema.NewStringColumn(\"name\", \"varchar(255)\"),\n\t\t\t\t\t\t).\n\t\t\t\t\t\tAddIndexes(\n\t\t\t\t\t\t\tschema.NewIndex(\"name_index\").\n\t\t\t\t\t\t\t\tAddParts(schema.NewColumnPart(schema.NewColumn(\"name\"))),\n\t\t\t\t\t\t)\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropIndex{\n\t\t\t\t\t\t\t\tI: users.Indexes[0],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` DROP INDEX `name_index`\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `users` ADD INDEX `name_index` (`name`)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Drop a primary key.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t)\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropPrimaryKey{\n\t\t\t\t\t\t\t\tP: schema.NewPrimaryKey(users.Columns...),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` DROP PRIMARY KEY\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `users` ADD PRIMARY KEY (`id`)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) { o.SchemaQualifier = new(string) },\n\t\t\t},\n\t\t},\n\t\t// Add a primary key.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t)\n\t\t\t\t\tusers.SetPrimaryKey(schema.NewPrimaryKey(users.Columns...))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddPrimaryKey{\n\t\t\t\t\t\t\t\tP: users.PrimaryKey,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `dev`.`users` ADD PRIMARY KEY (`id`)\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `dev`.`users` DROP PRIMARY KEY\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) {\n\t\t\t\t\tdev := \"dev\"\n\t\t\t\t\to.SchemaQualifier = &dev\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Modify a primary key.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewStringColumn(\"id\", \"varchar(255)\"),\n\t\t\t\t\t\t)\n\t\t\t\t\tusers.SetPrimaryKey(schema.NewPrimaryKey(users.Columns...))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifyPrimaryKey{\n\t\t\t\t\t\t\t\tFrom: schema.NewPrimaryKey(users.Columns...).\n\t\t\t\t\t\t\t\t\tAddAttrs(&IndexType{T: IndexTypeHash}),\n\t\t\t\t\t\t\t\tTo: users.PrimaryKey,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` DROP PRIMARY KEY, ADD PRIMARY KEY (`id`)\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `users` DROP PRIMARY KEY, ADD PRIMARY KEY USING HASH (`id`)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\tpets := &schema.Table{\n\t\t\t\t\t\tName: \"pets\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t{Name: \"user_id\",\n\t\t\t\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\t\t\t\tType: &schema.IntegerType{T: \"bigint\"},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\tfk := &schema.ForeignKey{\n\t\t\t\t\t\tSymbol:     \"user_id\",\n\t\t\t\t\t\tTable:      pets,\n\t\t\t\t\t\tOnUpdate:   schema.NoAction,\n\t\t\t\t\t\tOnDelete:   schema.Cascade,\n\t\t\t\t\t\tRefTable:   users,\n\t\t\t\t\t\tColumns:    []*schema.Column{pets.Columns[1]},\n\t\t\t\t\t\tRefColumns: []*schema.Column{users.Columns[0]},\n\t\t\t\t\t}\n\t\t\t\t\tpets.ForeignKeys = []*schema.ForeignKey{fk}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: pets,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropForeignKey{\n\t\t\t\t\t\t\t\tF: fk,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `pets` DROP FOREIGN KEY `user_id`\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `pets` ADD CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddSchema{S: &schema.Schema{Name: \"test\", Attrs: []schema.Attr{&schema.Charset{V: \"latin\"}}}},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges:    []*migrate.Change{{Cmd: \"CREATE DATABASE `test` CHARSET latin\", Reverse: \"DROP DATABASE `test`\"}},\n\t\t\t},\n\t\t},\n\t\t// Default database charset can be omitted.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddSchema{S: schema.New(\"test\").SetCharset(\"utf8\")},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges:    []*migrate.Change{{Cmd: \"CREATE DATABASE `test`\", Reverse: \"DROP DATABASE `test`\"}},\n\t\t\t},\n\t\t},\n\t\t// Add the default database charset on modify can be omitted.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifySchema{\n\t\t\t\t\tS: schema.New(\"test\").SetCharset(\"utf8\"),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.AddAttr{A: &schema.Charset{V: \"utf8\"}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t},\n\t\t},\n\t\t// Add custom charset.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifySchema{\n\t\t\t\t\tS: schema.New(\"test\").SetCharset(\"latin1\"),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.AddAttr{A: &schema.Charset{V: \"latin1\"}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges:    []*migrate.Change{{Cmd: \"ALTER DATABASE `test` CHARSET latin1\", Reverse: \"ALTER DATABASE `test` CHARSET utf8\"}},\n\t\t\t},\n\t\t},\n\t\t// Modify charset.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifySchema{\n\t\t\t\t\tS: schema.New(\"test\").SetCharset(\"utf8\"),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.ModifyAttr{From: &schema.Charset{V: \"latin1\"}, To: &schema.Charset{V: \"utf8\"}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges:    []*migrate.Change{{Cmd: \"ALTER DATABASE `test` CHARSET utf8\", Reverse: \"ALTER DATABASE `test` CHARSET latin1\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropSchema{S: &schema.Schema{Name: \"atlas\", Attrs: []schema.Attr{&schema.Charset{V: \"latin\"}}}},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tChanges: []*migrate.Change{{Cmd: \"DROP DATABASE `atlas`\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() *schema.AddTable {\n\t\t\t\t\tt := &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&AutoIncrement{}}},\n\t\t\t\t\t\t\t{Name: \"text\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Null: true}},\n\t\t\t\t\t\t\t{Name: \"uuid\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"char\", Size: 36}, Null: true}, Attrs: []schema.Attr{&schema.Charset{V: \"utf8mb4\"}, &schema.Collation{V: \"utf8mb4_bin\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\tt.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: t.Columns[0]}}}\n\t\t\t\t\tt.AddIndexes(\n\t\t\t\t\t\tschema.NewIndex(\"text\").\n\t\t\t\t\t\t\tAddParts(&schema.IndexPart{C: t.Columns[1]}).\n\t\t\t\t\t\t\tAddAttrs(&IndexType{T: \"FULLTEXT\"}, &schema.Comment{Text: \"text index\"}, &IndexParser{P: \"ngram\"}),\n\t\t\t\t\t)\n\t\t\t\t\treturn &schema.AddTable{T: t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"CREATE TABLE `posts` (`id` bigint NOT NULL AUTO_INCREMENT, `text` text NULL, `uuid` char(36) CHARSET utf8mb4 NULL COLLATE utf8mb4_bin, PRIMARY KEY (`id`), FULLTEXT INDEX `text` (`text`) COMMENT \\\"text index\\\" WITH PARSER `ngram`)\",\n\t\t\t\t\t\tReverse: \"DROP TABLE `posts`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() *schema.AddTable {\n\t\t\t\t\tt := &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&AutoIncrement{V: 100}}},\n\t\t\t\t\t\t\t{Name: \"text\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Null: true}},\n\t\t\t\t\t\t\t{Name: \"ch\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"char\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"utf8mb4_bin\"},\n\t\t\t\t\t\t\t&schema.Comment{Text: \"posts comment\"},\n\t\t\t\t\t\t\t&schema.Check{Name: \"id_nonzero\", Expr: \"(`id` > 0)\"},\n\t\t\t\t\t\t\t&CreateOptions{V: `COMPRESSION=\"ZLIB\"`},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tIndexes: []*schema.Index{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tName: \"text_prefix\",\n\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t{Desc: true, Attrs: []schema.Attr{&SubPart{Len: 100}}},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\tt.Indexes[0].Parts[0].C = t.Columns[1]\n\t\t\t\t\tt.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: t.Columns[0]}}}\n\t\t\t\t\treturn &schema.AddTable{T: t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges:    []*migrate.Change{{Cmd: \"CREATE TABLE `posts` (`id` bigint NOT NULL AUTO_INCREMENT, `text` text NULL, `ch` char NOT NULL, PRIMARY KEY (`id`), INDEX `text_prefix` (`text` (100) DESC), CONSTRAINT `id_nonzero` CHECK (`id` > 0)) CHARSET utf8mb4 COLLATE utf8mb4_bin COMMENT \\\"posts comment\\\" COMPRESSION=\\\"ZLIB\\\" AUTO_INCREMENT 100\", Reverse: \"DROP TABLE `posts`\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() *schema.AddTable {\n\t\t\t\t\tt := &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&AutoIncrement{}}},\n\t\t\t\t\t\t\t{Name: \"text\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Null: true}},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{&AutoIncrement{V: 10}},\n\t\t\t\t\t}\n\t\t\t\t\tt.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: t.Columns[0]}}}\n\t\t\t\t\treturn &schema.AddTable{T: t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges:    []*migrate.Change{{Cmd: \"CREATE TABLE `posts` (`id` bigint NOT NULL AUTO_INCREMENT, `text` text NULL, PRIMARY KEY (`id`)) AUTO_INCREMENT 10\", Reverse: \"DROP TABLE `posts`\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropTable{T: schema.NewTable(\"posts\").AddColumns(schema.NewIntColumn(\"id\", \"bigint\"))},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"DROP TABLE `posts`\",\n\t\t\t\t\t\tReverse: \"CREATE TABLE `posts` (`id` bigint NOT NULL)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: &schema.Column{Name: \"name\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(255)\"}}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tName: \"id_key\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0]},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t\t&schema.Comment{Text: \"comment\"},\n\t\t\t\t\t\t\t\t\t\t&IndexType{T: IndexTypeHash},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddCheck{\n\t\t\t\t\t\t\t\tC: &schema.Check{\n\t\t\t\t\t\t\t\t\tName:  \"id_nonzero\",\n\t\t\t\t\t\t\t\t\tExpr:  \"(id > 0)\",\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{&Enforced{}},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\t\t\t\tFrom: &AutoIncrement{V: 1},\n\t\t\t\t\t\t\t\tTo:   &AutoIncrement{V: 1000},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` ADD COLUMN `name` varchar(255) NOT NULL, ADD INDEX `id_key` USING HASH (`id`) COMMENT \\\"comment\\\", ADD CONSTRAINT `id_nonzero` CHECK (id > 0) ENFORCED, AUTO_INCREMENT 1000\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `users` AUTO_INCREMENT 1, DROP CONSTRAINT `id_nonzero`, DROP INDEX `id_key`, DROP COLUMN `name`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\"))\n\t\t\t\t\tposts := schema.NewTable(\"posts\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"author_id\", \"int\"),\n\t\t\t\t\t\t)\n\t\t\t\t\tposts.AddForeignKeys(\n\t\t\t\t\t\tschema.NewForeignKey(\"author\").\n\t\t\t\t\t\t\tAddColumns(posts.Columns[1]).\n\t\t\t\t\t\t\tSetRefTable(users).\n\t\t\t\t\t\t\tAddRefColumns(users.Columns[0]),\n\t\t\t\t\t)\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: posts,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddColumn{C: posts.Columns[1]},\n\t\t\t\t\t\t\t&schema.AddForeignKey{F: posts.ForeignKeys[0]},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `posts` ADD COLUMN `author_id` int NOT NULL, ADD CONSTRAINT `author` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`)\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `posts` DROP FOREIGN KEY `author`, DROP COLUMN `author_id`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"c1\", \"int\"))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: schema.NewIntColumn(\"c2\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"c1*2\"}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: schema.NewIntColumn(\"c3\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"c1*c2\", Type: \"STORED\"}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` ADD COLUMN `c2` int AS (c1*2) NOT NULL, ADD COLUMN `c3` int AS (c1*c2) STORED NOT NULL\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `users` DROP COLUMN `c3`, DROP COLUMN `c2`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropCheck{\n\t\t\t\t\t\t\t\tC: &schema.Check{\n\t\t\t\t\t\t\t\t\tName:  \"id_nonzero\",\n\t\t\t\t\t\t\t\t\tExpr:  \"(id > 0)\",\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{&Enforced{}},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` DROP CONSTRAINT `id_nonzero`\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `users` ADD CONSTRAINT `id_nonzero` CHECK (id > 0) ENFORCED\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifyCheck{\n\t\t\t\t\t\t\t\tFrom: &schema.Check{\n\t\t\t\t\t\t\t\t\tName:  \"check1\",\n\t\t\t\t\t\t\t\t\tExpr:  \"(id > 0)\",\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{&Enforced{}},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tTo: &schema.Check{\n\t\t\t\t\t\t\t\t\tName: \"check1\",\n\t\t\t\t\t\t\t\t\tExpr: \"(id > 0)\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyCheck{\n\t\t\t\t\t\t\t\tFrom: &schema.Check{\n\t\t\t\t\t\t\t\t\tName: \"check2\",\n\t\t\t\t\t\t\t\t\tExpr: \"(id > 0)\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tTo: &schema.Check{\n\t\t\t\t\t\t\t\t\tName:  \"check2\",\n\t\t\t\t\t\t\t\t\tExpr:  \"(id > 0)\",\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{&Enforced{}},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyCheck{\n\t\t\t\t\t\t\t\tFrom: &schema.Check{\n\t\t\t\t\t\t\t\t\tName: \"check3\",\n\t\t\t\t\t\t\t\t\tExpr: \"(id > 0)\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tTo: &schema.Check{\n\t\t\t\t\t\t\t\t\tName: \"check3\",\n\t\t\t\t\t\t\t\t\tExpr: \"(id >= 0)\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` ALTER CHECK `check1` ENFORCED, ALTER CHECK `check2` NOT ENFORCED, DROP CHECK `check3`, ADD CONSTRAINT `check3` CHECK (id >= 0)\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `users` DROP CHECK `check3`, ADD CONSTRAINT `check3` CHECK (id > 0), ALTER CHECK `check2` ENFORCED, ALTER CHECK `check1` NOT ENFORCED\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").AddColumns(schema.NewIntColumn(\"id\", \"bigint\").SetCharset(\"utf8mb4\")),\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").AddColumns(schema.NewIntColumn(\"id\", \"bigint\").SetCollation(\"utf8mb4_general_ci\")),\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t// Changing a regular column to a VIRTUAL generated column is not allowed.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewColumn(\"c\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\"})),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tChange: schema.ChangeGenerated,\n\t\t\t\t\t\t\tFrom:   schema.NewColumn(\"c\"),\n\t\t\t\t\t\t\tTo:     schema.NewColumn(\"c\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\"}),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t// Changing a VIRTUAL generated column to a regular column is not allowed.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewColumn(\"c\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tChange: schema.ChangeGenerated,\n\t\t\t\t\t\t\tFrom:   schema.NewColumn(\"c\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"VIRTUAL\"}),\n\t\t\t\t\t\t\tTo:     schema.NewColumn(\"c\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t// Changing the storage type of generated column is not allowed.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewColumn(\"c\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"})),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tChange: schema.ChangeGenerated,\n\t\t\t\t\t\t\tFrom:   schema.NewColumn(\"c\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"VIRTUAL\"}),\n\t\t\t\t\t\t\tTo:     schema.NewColumn(\"c\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t// Changing a STORED generated column to a regular column.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"c\", \"int\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tChange: schema.ChangeGenerated,\n\t\t\t\t\t\t\tFrom:   schema.NewIntColumn(\"c\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\t\tTo:     schema.NewIntColumn(\"c\", \"int\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` MODIFY COLUMN `c` int NOT NULL\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `users` MODIFY COLUMN `c` int AS (1) STORED NOT NULL\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Changing a regular column to a STORED generated column.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"c\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\t),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tChange: schema.ChangeGenerated,\n\t\t\t\t\t\t\tFrom:   schema.NewIntColumn(\"c\", \"int\"),\n\t\t\t\t\t\t\tTo:     schema.NewIntColumn(\"c\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tChange: schema.ChangeGenerated,\n\t\t\t\t\t\t\tFrom:   schema.NewIntColumn(\"c0\", \"int\"),\n\t\t\t\t\t\t\tTo:     schema.NewIntColumn(\"c1\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `users` MODIFY COLUMN `c` int AS (1) STORED NOT NULL, CHANGE COLUMN `c0` `c1` int AS (1) STORED NOT NULL\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `users` CHANGE COLUMN `c1` `c0` int NOT NULL, MODIFY COLUMN `c` int NOT NULL\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.RenameTable{\n\t\t\t\t\tFrom: schema.NewTable(\"t1\"),\n\t\t\t\t\tTo:   schema.NewTable(\"t2\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"RENAME TABLE `t1` TO `t2`\",\n\t\t\t\t\t\tReverse: \"RENAME TABLE `t2` TO `t1`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.RenameTable{\n\t\t\t\t\tFrom: schema.NewTable(\"t1\").SetSchema(schema.New(\"s1\")),\n\t\t\t\t\tTo:   schema.NewTable(\"t2\").SetSchema(schema.New(\"s2\")),\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"RENAME TABLE `s1`.`t1` TO `s2`.`t2`\",\n\t\t\t\t\t\tReverse: \"RENAME TABLE `s2`.`t2` TO `s1`.`t1`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\t\t\tSetSchema(schema.New(\"s1\")).\n\t\t\t\t\t\tAddColumns(schema.NewColumn(\"b\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameColumn{\n\t\t\t\t\t\t\tFrom: schema.NewColumn(\"a\"),\n\t\t\t\t\t\t\tTo:   schema.NewColumn(\"b\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `s1`.`t1` RENAME COLUMN `a` TO `b`\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `s1`.`t1` RENAME COLUMN `b` TO `a`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tversion: \"5.6\",\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\t\t\tSetSchema(schema.New(\"s1\")).\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"b\", \"int\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameColumn{\n\t\t\t\t\t\t\tFrom: schema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\t\t\tTo:   schema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `s1`.`t1` CHANGE COLUMN `a` `b` int NOT NULL\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `s1`.`t1` CHANGE COLUMN `b` `a` int NOT NULL\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\t\t\tSetSchema(schema.New(\"s1\")).\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"b\", \"int\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameIndex{\n\t\t\t\t\t\t\tFrom: schema.NewIndex(\"a\"),\n\t\t\t\t\t\t\tTo:   schema.NewIndex(\"b\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `s1`.`t1` RENAME INDEX `a` TO `b`\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `s1`.`t1` RENAME INDEX `b` TO `a`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Empty qualifier.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{T: schema.NewTable(\"t\").SetSchema(schema.New(\"d\")).AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) { o.SchemaQualifier = new(string) },\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"CREATE TABLE `t` (`a` int NOT NULL)\",\n\t\t\t\t\t\tReverse: \"DROP TABLE `t`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Custom qualifier.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{T: schema.NewTable(\"t\").SetSchema(schema.New(\"d\")).AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) {\n\t\t\t\t\ts := \"other\"\n\t\t\t\t\to.SchemaQualifier = &s\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"CREATE TABLE `other`.`t` (`a` int NOT NULL)\",\n\t\t\t\t\t\tReverse: \"DROP TABLE `other`.`t`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Empty qualifier in multi-schema mode should fail.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{T: schema.NewTable(\"t1\").SetSchema(schema.New(\"s1\")).AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t\t\t\t&schema.AddTable{T: schema.NewTable(\"t2\").SetSchema(schema.New(\"s2\")).AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) { o.SchemaQualifier = new(string) },\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tif tt.version == \"\" {\n\t\t\t\ttt.version = \"8.0.16\"\n\t\t\t}\n\t\t\tdb, _, err := newMigrate(tt.version)\n\t\t\trequire.NoError(t, err)\n\t\t\tplan, err := db.PlanChanges(context.Background(), \"wantPlan\", tt.changes, tt.options...)\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err, \"expect plan to fail\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, plan)\n\t\t\trequire.Equal(t, tt.wantPlan.Reversible, plan.Reversible)\n\t\t\trequire.Equal(t, tt.wantPlan.Transactional, plan.Transactional)\n\t\t\trequire.Equal(t, len(tt.wantPlan.Changes), len(plan.Changes))\n\t\t\tfor i, c := range plan.Changes {\n\t\t\t\trequire.Equal(t, tt.wantPlan.Changes[i].Cmd, c.Cmd)\n\t\t\t\trequire.Equal(t, tt.wantPlan.Changes[i].Reverse, c.Reverse)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestDefaultPlan(t *testing.T) {\n\tchanges, err := DefaultPlan.PlanChanges(context.Background(), \"plan\", []schema.Change{\n\t\t&schema.AddTable{T: schema.NewTable(\"t1\").SetSchema(schema.New(\"s1\")).AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, 1, len(changes.Changes))\n\trequire.Equal(t, \"CREATE TABLE `s1`.`t1` (`a` int NOT NULL)\", changes.Changes[0].Cmd)\n\n\terr = DefaultPlan.ApplyChanges(context.Background(), []schema.Change{\n\t\t&schema.AddTable{T: schema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t})\n\trequire.EqualError(t, err, `create \"t1\" table: cannot execute statements without a database connection. use Open to create a new Driver`)\n}\n\nfunc TestIndentedPlan(t *testing.T) {\n\ttests := []struct {\n\t\tT   *schema.Table\n\t\tCmd string\n\t}{\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"s1\")).\n\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `s1`.`t1` (\",\n\t\t\t\t\"  `a` int NOT NULL\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tSetPrimaryKey(\n\t\t\t\t\tschema.NewPrimaryKey(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\t),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL,\",\n\t\t\t\t\"  `id` int NOT NULL,\",\n\t\t\t\t\"  PRIMARY KEY (`id`)\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewIndex(\"idx\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t\t\t),\n\t\t\t\t),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL,\",\n\t\t\t\t\"  INDEX `idx` (`a`, `b`)\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tSetPrimaryKey(\n\t\t\t\t\tschema.NewPrimaryKey(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\t).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewIndex(\"idx\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t\t\t),\n\t\t\t\t),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL,\",\n\t\t\t\t\"  `id` int NOT NULL,\",\n\t\t\t\t\"  PRIMARY KEY (`id`),\",\n\t\t\t\t\"  INDEX `idx` (`a`, `b`)\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewIndex(\"idx1\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t\t\t),\n\t\t\t\t\tschema.NewIndex(\"idx2\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t\t\t),\n\t\t\t\t),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL,\",\n\t\t\t\t\"  INDEX `idx1` (`a`, `b`),\",\n\t\t\t\t\"  INDEX `idx2` (`a`, `b`)\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewIndex(\"idx1\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t\t\t),\n\t\t\t\t\tschema.NewIndex(\"idx2\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t\t\t),\n\t\t\t\t).\n\t\t\t\tAddForeignKeys(\n\t\t\t\t\tschema.NewForeignKey(\"fk1\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t\tschema.NewForeignKey(\"fk2\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL,\",\n\t\t\t\t\"  INDEX `idx1` (`a`, `b`),\",\n\t\t\t\t\"  INDEX `idx2` (`a`, `b`),\",\n\t\t\t\t\"  CONSTRAINT `fk1` FOREIGN KEY (`a`) REFERENCES `t2` (`a`),\",\n\t\t\t\t\"  CONSTRAINT `fk2` FOREIGN KEY (`a`) REFERENCES `t2` (`a`)\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tSetPrimaryKey(\n\t\t\t\t\tschema.NewPrimaryKey(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\t).\n\t\t\t\tAddForeignKeys(\n\t\t\t\t\tschema.NewForeignKey(\"fk1\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t\tschema.NewForeignKey(\"fk2\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t).\n\t\t\t\tAddChecks(\n\t\t\t\t\tschema.NewCheck().SetName(\"ck1\").SetExpr(\"a > 0\"),\n\t\t\t\t\tschema.NewCheck().SetName(\"ck2\").SetExpr(\"a > 0\"),\n\t\t\t\t).\n\t\t\t\tSetComment(\"Comment\"),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL,\",\n\t\t\t\t\"  `id` int NOT NULL,\",\n\t\t\t\t\"  PRIMARY KEY (`id`),\",\n\t\t\t\t\"  CONSTRAINT `fk1` FOREIGN KEY (`a`) REFERENCES `t2` (`a`),\",\n\t\t\t\t\"  CONSTRAINT `fk2` FOREIGN KEY (`a`) REFERENCES `t2` (`a`),\",\n\t\t\t\t\"  CONSTRAINT `ck1` CHECK (a > 0),\",\n\t\t\t\t\"  CONSTRAINT `ck2` CHECK (a > 0)\",\n\t\t\t\t`) COMMENT \"Comment\"`,\n\t\t\t),\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tdb, _, err := newMigrate(\"8.0.16\")\n\t\t\trequire.NoError(t, err)\n\t\t\tplan, err := db.PlanChanges(context.Background(), \"wantPlan\", []schema.Change{&schema.AddTable{T: tt.T}}, func(opts *migrate.PlanOptions) {\n\t\t\t\topts.Indent = \"  \"\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, plan.Changes, 1)\n\t\t\trequire.Equal(t, tt.Cmd, plan.Changes[0].Cmd)\n\t\t})\n\t}\n}\n\nfunc newMigrate(version string) (migrate.PlanApplier, *mock, error) {\n\tdb, m, err := sqlmock.New()\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tmk := &mock{m}\n\tmk.version(version)\n\tdrv, err := Open(db)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn drv, mk, nil\n}\n\nfunc join(lines ...string) string { return strings.Join(lines, \"\\n\") }\n"
  },
  {
    "path": "sql/mysql/mysqlcheck/mysqlcheck.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage mysqlcheck\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/mysql\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlcheck/condrop\"\n\t\"ariga.io/atlas/sql/sqlcheck/datadepend\"\n\t\"ariga.io/atlas/sql/sqlcheck/destructive\"\n\t\"ariga.io/atlas/sql/sqlcheck/incompatible\"\n)\n\nvar (\n\t// codeImplicitUpdate is a MySQL specific code for reporting implicit update.\n\tcodeImplicitUpdate = sqlcheck.Code(\"MY101\")\n\t// codeInlineRef is a MySQL specific code for reporting columns with inline references.\n\tcodeInlineRef = sqlcheck.Code(\"MY102\")\n)\n\nfunc addNotNull(p *datadepend.ColumnPass) (diags []sqlcheck.Diagnostic, err error) {\n\t// Two types of reporting, implicit rows update and\n\t// changes that may cause the migration to fail.\n\tmightFail := func(tt string) {\n\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\tPos: p.Change.Stmt.Pos,\n\t\t\tText: fmt.Sprintf(\n\t\t\t\t\"Adding a non-nullable %q column %q will fail in case table %q is not empty\",\n\t\t\t\ttt, p.Column.Name, p.Table.Name,\n\t\t\t),\n\t\t})\n\t}\n\timplicitUpdate := func(tt, v string) {\n\t\tif !columnFilledAfter(p, v) {\n\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\tCode: codeImplicitUpdate,\n\t\t\t\tPos:  p.Change.Stmt.Pos,\n\t\t\t\tText: fmt.Sprintf(\n\t\t\t\t\t\"Adding a non-nullable %q column %q on table %q without a default value implicitly sets existing rows with %s\",\n\t\t\t\t\ttt, p.Column.Name, p.Table.Name, v,\n\t\t\t\t),\n\t\t\t})\n\t\t}\n\t}\n\tdrv, ok := p.Dev.Driver.(*mysql.Driver)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected migrate driver %T\", p.Dev.Driver)\n\t}\n\tswitch ct := p.Column.Type.Type.(type) {\n\tcase *mysql.BitType, *schema.BoolType, *schema.IntegerType, *schema.DecimalType, *schema.FloatType, *schema.BinaryType:\n\t\tif !sqlx.Has(p.Column.Attrs, &mysql.AutoIncrement{}) {\n\t\t\ttt, err := mysql.FormatType(p.Column.Type.Type)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\timplicitUpdate(tt, \"0\")\n\t\t}\n\tcase *schema.StringType:\n\t\tswitch ct.T {\n\t\tcase mysql.TypeVarchar, mysql.TypeChar:\n\t\t\timplicitUpdate(ct.T, `\"\"`)\n\t\tcase mysql.TypeText, mysql.TypeTinyText, mysql.TypeMediumText, mysql.TypeLongText:\n\t\t\t// On MySQL, Existing rows are updated with ''. Skip it\n\t\t\t// as we cannot propose and detect multi-steps migration\n\t\t\t// (ALTER + UPDATE) at this stage.\n\t\t\tif drv.Maria() {\n\t\t\t\timplicitUpdate(ct.T, `\"\"`)\n\t\t\t}\n\t\t}\n\tcase *schema.EnumType:\n\t\tif len(ct.Values) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"unexpected empty values for enum column %q.%q\", p.Table.Name, p.Column.Name)\n\t\t}\n\t\timplicitUpdate(\"enum\", strconv.Quote(ct.Values[0]))\n\tcase *mysql.SetType:\n\t\timplicitUpdate(\"set\", `\"\"`)\n\tcase *schema.JSONType:\n\t\t// On MySQL, Existing rows are updated with 'null' JSON. Same as TEXT\n\t\t// columns, we cannot propose multi-steps migration (ALTER + UPDATE)\n\t\t// as it cannot be detected at this stage.\n\t\tif drv.Maria() {\n\t\t\timplicitUpdate(ct.T, `\"\"`)\n\t\t}\n\tcase *schema.TimeType:\n\t\tswitch ct.T {\n\t\tcase mysql.TypeDate, mysql.TypeDateTime:\n\t\t\tif drv.Maria() {\n\t\t\t\timplicitUpdate(ct.T, \"00:00:00\")\n\t\t\t} else {\n\t\t\t\t// The suggested solution is to add a DEFAULT clause\n\t\t\t\t// with valid value or set the column to nullable.\n\t\t\t\tmightFail(ct.T)\n\t\t\t}\n\t\tcase mysql.TypeYear:\n\t\t\timplicitUpdate(ct.T, \"0000\")\n\t\tcase mysql.TypeTime:\n\t\t\timplicitUpdate(ct.T, \"00:00:00\")\n\t\tcase mysql.TypeTimestamp:\n\t\t\tv := \"CURRENT_TIMESTAMP\"\n\t\t\tswitch {\n\t\t\tcase drv.Maria():\n\t\t\t\t// Maria has a special behavior for the first TIMESTAMP column.\n\t\t\t\t// See: https://mariadb.com/kb/en/timestamp/#automatic-values\n\t\t\t\tfor i := 0; i < len(p.Table.Columns) && p.Table.Columns[i].Name != p.Column.Name; i++ {\n\t\t\t\t\ttt, err := mysql.FormatType(p.Table.Columns[i].Type.Type)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tif strings.HasPrefix(tt, mysql.TypeTimestamp) {\n\t\t\t\t\t\tv = \"0000-00-00 00:00:00\"\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t// Following MySQL 8.0.2, the explicit_defaults_for_timestamp\n\t\t\t// system variable is now enabled by default.\n\t\t\tcase drv.GTE(\"8.0.2\"):\n\t\t\t\tv = \"0000-00-00 00:00:00\"\n\t\t\t}\n\t\t\timplicitUpdate(ct.T, v)\n\t\t}\n\tcase *schema.SpatialType:\n\t\tif drv.Maria() {\n\t\t\timplicitUpdate(ct.T, `\"\"`)\n\t\t} else {\n\t\t\t// The suggested solution is to add the column as\n\t\t\t// null, update values and then set it to not-null.\n\t\t\tmightFail(ct.T)\n\t\t}\n\t}\n\treturn\n}\n\n// columnFilledAfter checks if the column with the given value was filled after the current change.\nfunc columnFilledAfter(pass *datadepend.ColumnPass, matchValue string) bool {\n\tp, ok := pass.File.Parser.(interface {\n\t\tColumnFilledAfter([]*migrate.Stmt, *schema.Table, *schema.Column, int, any) (bool, error)\n\t})\n\tif !ok {\n\t\treturn false\n\t}\n\tstmts, err := migrate.FileStmtDecls(pass.Dev, pass.File)\n\tif err != nil {\n\t\treturn false\n\t}\n\tfilled, _ := p.ColumnFilledAfter(stmts, pass.Table, pass.Column, pass.Change.Stmt.Pos, matchValue)\n\treturn filled\n}\n\n// inlineRefs is an analyzer function that detects column definitions with the REFERENCES\n// clause and suggest replacing them with an explicit foreign-key definition.\nfunc inlineRefs(_ context.Context, p *sqlcheck.Pass) error {\n\tvar diags []sqlcheck.Diagnostic\n\tparse, ok := p.File.Parser.(interface {\n\t\tColumnHasReferences(*migrate.Stmt, *schema.Column) (bool, error)\n\t})\n\tif !ok {\n\t\treturn nil\n\t}\n\tfor _, sc := range p.File.Changes {\n\t\tfor _, c := range sc.Changes {\n\t\t\tswitch c := c.(type) {\n\t\t\tcase *schema.AddTable:\n\t\t\t\tfor i := range c.T.Columns {\n\t\t\t\t\tif hasR, _ := parse.ColumnHasReferences(sc.Stmt, c.T.Columns[i]); hasR {\n\t\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\t\tCode: codeInlineRef,\n\t\t\t\t\t\t\tText: fmt.Sprintf(\"Defining column %q on table %q with inline REFERENCES is ignored by MySQL\", c.T.Columns[i].Name, c.T.Name),\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase *schema.ModifyTable:\n\t\t\t\tfor _, mc := range c.Changes {\n\t\t\t\t\tadd, ok := mc.(*schema.AddColumn)\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif hasR, _ := parse.ColumnHasReferences(sc.Stmt, add.C); hasR {\n\t\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\t\tCode: codeInlineRef,\n\t\t\t\t\t\t\tText: fmt.Sprintf(\"Defining column %q on table %q with inline REFERENCES is ignored by MySQL\", add.C.Name, c.T.Name),\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif len(diags) > 0 {\n\t\tp.Reporter.WriteReport(sqlcheck.Report{Text: \"inline REFERENCES detected\", Diagnostics: diags})\n\t}\n\treturn nil\n}\n\nfunc analyzers(r *schemahcl.Resource) ([]sqlcheck.Analyzer, error) {\n\tds, err := destructive.New(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcd, err := condrop.New(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdd, err := datadepend.New(r, datadepend.Handler{\n\t\tAddNotNull: addNotNull,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbc, err := incompatible.New(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []sqlcheck.Analyzer{ds, dd, cd, bc, sqlcheck.AnalyzerFunc(inlineRefs)}, nil\n}\n"
  },
  {
    "path": "sql/mysql/mysqlcheck/mysqlcheck_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysqlcheck\n\nimport (\n\t\"ariga.io/atlas/sql/mysql\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n)\n\nfunc init() {\n\tsqlcheck.Register(mysql.DriverName, analyzers)\n}\n"
  },
  {
    "path": "sql/mysql/mysqlcheck/mysqlcheck_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage mysqlcheck_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/internal/sqltest\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/mysql\"\n\t_ \"ariga.io/atlas/sql/mysql/mysqlcheck\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDataDepend_MySQL_ImplicitUpdate(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{\n\t\t\t\tName:   \"mysql\",\n\t\t\t\tDriver: devDriver(t, \"5.7.0\"),\n\t\t\t},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE users\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", mysql.TypeInt),\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"b\", mysql.TypeInt),\n\t\t\t\t\t\t\t\t\t\tschema.NewFloatColumn(\"c\", mysql.TypeFloat),\n\t\t\t\t\t\t\t\t\t\tschema.NewStringColumn(\"d\", mysql.TypeVarchar, schema.StringSize(10)),\n\t\t\t\t\t\t\t\t\t\tschema.NewEnumColumn(\"e\", schema.EnumValues(\"foo\", \"bar\")),\n\t\t\t\t\t\t\t\t\t\tschema.NewTimeColumn(\"f\", mysql.TypeTimestamp),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewIntColumn(\"b\", mysql.TypeInt)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewFloatColumn(\"c\", mysql.TypeFloat)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewStringColumn(\"d\", mysql.TypeVarchar, schema.StringSize(10))},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewEnumColumn(\"e\", schema.EnumValues(\"foo\", \"bar\"))},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewTimeColumn(\"f\", mysql.TypeTimestamp)},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\tazs, err := sqlcheck.AnalyzerFor(mysql.DriverName, nil)\n\trequire.NoError(t, err)\n\trequire.NoError(t, sqlcheck.Analyzers(azs).Analyze(context.Background(), pass))\n\trequire.Equal(t, report.Diagnostics[0].Text, `Adding a non-nullable \"int\" column \"b\" on table \"users\" without a default value implicitly sets existing rows with 0`)\n\trequire.Equal(t, report.Diagnostics[1].Text, `Adding a non-nullable \"float\" column \"c\" on table \"users\" without a default value implicitly sets existing rows with 0`)\n\trequire.Equal(t, report.Diagnostics[2].Text, `Adding a non-nullable \"varchar\" column \"d\" on table \"users\" without a default value implicitly sets existing rows with \"\"`)\n\trequire.Equal(t, report.Diagnostics[3].Text, `Adding a non-nullable \"enum\" column \"e\" on table \"users\" without a default value implicitly sets existing rows with \"foo\"`)\n\trequire.Equal(t, report.Diagnostics[4].Text, `Adding a non-nullable \"timestamp\" column \"f\" on table \"users\" without a default value implicitly sets existing rows with CURRENT_TIMESTAMP`)\n}\n\nfunc TestDataDepend_MySQL8_ImplicitUpdate(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{\n\t\t\t\tName:   \"mysql\",\n\t\t\t\tDriver: devDriver(t, \"8.0.19\"),\n\t\t\t},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE users\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", mysql.TypeInt),\n\t\t\t\t\t\t\t\t\t\tschema.NewTimeColumn(\"b\", mysql.TypeTimestamp),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewTimeColumn(\"b\", mysql.TypeTimestamp)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewIntColumn(\"id\", mysql.TypeBigInt).AddAttrs(&mysql.AutoIncrement{})},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\tazs, err := sqlcheck.AnalyzerFor(mysql.DriverName, nil)\n\trequire.NoError(t, err)\n\trequire.NoError(t, sqlcheck.Analyzers(azs).Analyze(context.Background(), pass))\n\trequire.Equal(t,\n\t\treport.Diagnostics[0].Text,\n\t\t`Adding a non-nullable \"timestamp\" column \"b\" on table \"users\" without a default value implicitly sets existing rows with 0000-00-00 00:00:00`,\n\t\t\"explicit_defaults_for_timestamp is enabled by default for versions >= 8.0.2\",\n\t)\n}\n\nfunc TestDataDepend_MySQL_MightFail(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{\n\t\t\t\tName:   \"mysql\",\n\t\t\t\tDriver: devDriver(t, \"8.0.19\"),\n\t\t\t},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE users\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", mysql.TypeInt),\n\t\t\t\t\t\t\t\t\t\tschema.NewTimeColumn(\"b\", mysql.TypeDate),\n\t\t\t\t\t\t\t\t\t\tschema.NewTimeColumn(\"c\", mysql.TypeDateTime),\n\t\t\t\t\t\t\t\t\t\tschema.NewSpatialColumn(\"d\", mysql.TypePoint),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewTimeColumn(\"b\", mysql.TypeDate)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewTimeColumn(\"c\", mysql.TypeDateTime)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewSpatialColumn(\"d\", mysql.TypePoint)},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\tazs, err := sqlcheck.AnalyzerFor(mysql.DriverName, nil)\n\trequire.NoError(t, err)\n\trequire.NoError(t, sqlcheck.Analyzers(azs).Analyze(context.Background(), pass))\n\trequire.Equal(t, report.Diagnostics[0].Text, `Adding a non-nullable \"date\" column \"b\" will fail in case table \"users\" is not empty`)\n\trequire.Equal(t, report.Diagnostics[1].Text, `Adding a non-nullable \"datetime\" column \"c\" will fail in case table \"users\" is not empty`)\n\trequire.Equal(t, report.Diagnostics[2].Text, `Adding a non-nullable \"point\" column \"d\" will fail in case table \"users\" is not empty`)\n}\n\nfunc TestDataDepend_Maria_ImplicitUpdate(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{\n\t\t\t\tName:   \"mysql\",\n\t\t\t\tDriver: devDriver(t, \"10.7.1-MariaDB\"),\n\t\t\t},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE users\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", mysql.TypeInt),\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"b\", mysql.TypeText),\n\t\t\t\t\t\t\t\t\t\tschema.NewJSONColumn(\"c\", mysql.TypeJSON),\n\t\t\t\t\t\t\t\t\t\tschema.NewTimeColumn(\"d\", mysql.TypeDate),\n\t\t\t\t\t\t\t\t\t\tschema.NewTimeColumn(\"e\", mysql.TypeDateTime),\n\t\t\t\t\t\t\t\t\t\tschema.NewSpatialColumn(\"f\", mysql.TypePoint),\n\t\t\t\t\t\t\t\t\t\tschema.NewTimeColumn(\"first_ts\", mysql.TypeTimestamp),\n\t\t\t\t\t\t\t\t\t\tschema.NewTimeColumn(\"second_ts\", mysql.TypeTimestamp),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewStringColumn(\"b\", mysql.TypeText)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewJSONColumn(\"c\", mysql.TypeJSON)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewTimeColumn(\"d\", mysql.TypeDate)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewTimeColumn(\"e\", mysql.TypeDateTime)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewSpatialColumn(\"f\", mysql.TypePoint)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewTimeColumn(\"first_ts\", mysql.TypeTimestamp)},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewTimeColumn(\"second_ts\", mysql.TypeTimestamp)},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\tazs, err := sqlcheck.AnalyzerFor(mysql.DriverName, nil)\n\trequire.NoError(t, err)\n\trequire.NoError(t, sqlcheck.Analyzers(azs).Analyze(context.Background(), pass))\n\trequire.Equal(t, report.Diagnostics[0].Text, `Adding a non-nullable \"text\" column \"b\" on table \"users\" without a default value implicitly sets existing rows with \"\"`)\n\trequire.Equal(t, report.Diagnostics[1].Text, `Adding a non-nullable \"json\" column \"c\" on table \"users\" without a default value implicitly sets existing rows with \"\"`)\n\trequire.Equal(t, report.Diagnostics[2].Text, `Adding a non-nullable \"date\" column \"d\" on table \"users\" without a default value implicitly sets existing rows with 00:00:00`)\n\trequire.Equal(t, report.Diagnostics[3].Text, `Adding a non-nullable \"datetime\" column \"e\" on table \"users\" without a default value implicitly sets existing rows with 00:00:00`)\n\trequire.Equal(t, report.Diagnostics[4].Text, `Adding a non-nullable \"point\" column \"f\" on table \"users\" without a default value implicitly sets existing rows with \"\"`)\n\trequire.Equal(t, report.Diagnostics[5].Text, `Adding a non-nullable \"timestamp\" column \"first_ts\" on table \"users\" without a default value implicitly sets existing rows with CURRENT_TIMESTAMP`)\n\trequire.Equal(t, report.Diagnostics[6].Text, `Adding a non-nullable \"timestamp\" column \"second_ts\" on table \"users\" without a default value implicitly sets existing rows with 0000-00-00 00:00:00`)\n\n}\n\ntype testFile struct {\n\tname string\n\tmigrate.File\n}\n\nfunc (t testFile) Name() string {\n\treturn t.name\n}\n\nfunc devDriver(t *testing.T, version string) migrate.Driver {\n\tdb, mk, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmk.ExpectQuery(\"SELECT @@version, @@collation_server, @@character_set_server, @@lower_case_table_name\").\n\t\tWillReturnRows(sqltest.Rows(`\n+-----------------+--------------------+------------------------+--------------------------+ \n| @@version       | @@collation_server | @@character_set_server | @@lower_case_table_names | \n+-----------------+--------------------+------------------------+--------------------------+ \n|` + version + `  | utf8_general_ci    | utf8                   | 0                        | \n+-----------------+--------------------+------------------------+--------------------------+ \n`))\n\tdrv, err := mysql.Open(db)\n\trequire.NoError(t, err)\n\treturn drv\n}\n"
  },
  {
    "path": "sql/mysql/sqlspec_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysql\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/specutil\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlspec\"\n\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\n// Codec for schemahcl.\ntype Codec struct {\n\tState *schemahcl.State\n}\n\n// Eval evaluates an Atlas DDL document into v using the input.\nfunc (c *Codec) Eval(p *hclparse.Parser, v any, input map[string]cty.Value) error {\n\treturn c.EvalOptions(p, v, &schemahcl.EvalOptions{Variables: input})\n}\n\n// EvalOptions decodes the HCL with the given options.\nfunc (c *Codec) EvalOptions(p *hclparse.Parser, v any, opts *schemahcl.EvalOptions) error {\n\tswitch v := v.(type) {\n\tcase *schema.Realm:\n\t\tvar d specutil.Doc\n\t\tif err := c.State.EvalOptions(p, &d, opts); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := specutil.Scan(v,\n\t\t\t&specutil.ScanDoc{Schemas: d.Schemas, Tables: d.Tables, Views: d.Views, Funcs: d.Funcs, Procs: d.Procs, Triggers: d.Triggers},\n\t\t\tscanFuncs,\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"mysql: failed converting to *schema.Realm: %w\", err)\n\t\t}\n\t\tfor _, spec := range d.Schemas {\n\t\t\ts, ok := v.Schema(spec.Name)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"could not find schema: %q\", spec.Name)\n\t\t\t}\n\t\t\tif err := convertCharset(spec, &s.Attrs); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\tcase *schema.Schema:\n\t\tvar d specutil.Doc\n\t\tif err := c.State.EvalOptions(p, &d, opts); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(d.Schemas) != 1 {\n\t\t\treturn fmt.Errorf(\"mysql: expecting document to contain a single schema, got %d\", len(d.Schemas))\n\t\t}\n\t\tr := &schema.Realm{}\n\t\tif err := specutil.Scan(r,\n\t\t\t&specutil.ScanDoc{Schemas: d.Schemas, Tables: d.Tables, Views: d.Views, Funcs: d.Funcs, Procs: d.Procs, Triggers: d.Triggers},\n\t\t\tscanFuncs,\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := convertCharset(d.Schemas[0], &r.Schemas[0].Attrs); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t*v = *r.Schemas[0]\n\tcase schema.Schema, schema.Realm:\n\t\treturn fmt.Errorf(\"mysql: Eval expects a pointer: received %[1]T, expected *%[1]T\", v)\n\tdefault:\n\t\treturn fmt.Errorf(\"mysql: unexpected type %T\", v)\n\t}\n\treturn nil\n}\n\n// MarshalSpec marshals v into an Atlas DDL document using a schemahcl.Marshaler.\nfunc (c *Codec) MarshalSpec(v any) ([]byte, error) {\n\treturn specutil.Marshal(v, c.State, specutil.RealmFuncs{\n\t\tSchema:   schemaSpec,\n\t\tTriggers: triggersSpec,\n\t})\n}\n\nfunc triggersSpec([]*schema.Trigger, *specutil.Doc) ([]*sqlspec.Trigger, error) {\n\treturn nil, nil // unimplemented.\n}\n\nvar (\n\tregistrySpecs     = TypeRegistry.Specs()\n\tsharedSpecOptions = []schemahcl.Option{\n\t\tschemahcl.WithTypes(\"table.column.type\", registrySpecs),\n\t\tschemahcl.WithTypes(\"view.column.type\", registrySpecs),\n\t\tschemahcl.WithScopedEnums(\"view.check_option\", schema.ViewCheckOptionLocal, schema.ViewCheckOptionCascaded),\n\t\tschemahcl.WithScopedEnums(\"table.engine\", EngineInnoDB, EngineMyISAM, EngineMemory, EngineCSV, EngineNDB),\n\t\tschemahcl.WithScopedEnums(\"table.index.type\", IndexTypeBTree, IndexTypeHash, IndexTypeFullText, IndexTypeSpatial),\n\t\tschemahcl.WithScopedEnums(\"table.index.parser\", IndexParserNGram, IndexParserMeCab),\n\t\tschemahcl.WithScopedEnums(\"table.primary_key.type\", IndexTypeBTree, IndexTypeHash, IndexTypeFullText, IndexTypeSpatial),\n\t\tschemahcl.WithScopedEnums(\"table.column.as.type\", stored, persistent, virtual),\n\t\tschemahcl.WithScopedEnums(\"table.foreign_key.on_update\", specutil.ReferenceVars...),\n\t\tschemahcl.WithScopedEnums(\"table.foreign_key.on_delete\", specutil.ReferenceVars...),\n\t}\n\tcodec = &Codec{\n\t\tState: schemahcl.New(\n\t\t\tappend(\n\t\t\t\tspecOptions,\n\t\t\t\tsharedSpecOptions...,\n\t\t\t)...,\n\t\t),\n\t}\n\tmariaCodec = &Codec{\n\t\tState: schemahcl.New(\n\t\t\tappend(\n\t\t\t\tmariaSpecOptions,\n\t\t\t\tsharedSpecOptions...,\n\t\t\t)...,\n\t\t),\n\t}\n\t// MarshalHCL marshals v into an Atlas HCL DDL document.\n\tMarshalHCL = schemahcl.MarshalerFunc(codec.MarshalSpec)\n\t// EvalHCL implements the schemahcl.Evaluator interface.\n\tEvalHCL = schemahcl.EvalFunc(codec.Eval)\n\t// EvalHCLBytes is a helper that evaluates an HCL document from a byte slice.\n\tEvalHCLBytes = specutil.HCLBytesFunc(EvalHCL)\n\t// EvalMariaHCL implements the schemahcl.Evaluator interface for MariaDB flavor.\n\tEvalMariaHCL = schemahcl.EvalFunc(mariaCodec.Eval)\n\t// EvalMariaHCLBytes is a helper that evaluates a MariaDB HCL document from a byte slice.\n\tEvalMariaHCLBytes             = specutil.HCLBytesFunc(EvalMariaHCL)\n\tspecOptions, mariaSpecOptions []schemahcl.Option\n\tspecFuncs                     = &specutil.SchemaFuncs{\n\t\tTable: tableSpec,\n\t\tView:  viewSpec,\n\t}\n\tscanFuncs = &specutil.ScanFuncs{\n\t\tTable: convertTable,\n\t\tView:  convertView,\n\t}\n)\n\n// convertTable converts a sqlspec.Table to a schema.Table. Table conversion is done without converting\n// ForeignKeySpecs into ForeignKeys, as the target tables do not necessarily exist in the schema\n// at this point. Instead, the linking is done by the convertSchema function.\nfunc convertTable(spec *sqlspec.Table, parent *schema.Schema) (*schema.Table, error) {\n\tt, err := specutil.Table(spec, parent, convertColumn, convertPK, convertIndex, convertCheck)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := convertCharset(spec, &t.Attrs); err != nil {\n\t\treturn nil, err\n\t}\n\t// MySQL allows setting the initial AUTO_INCREMENT value\n\t// on the table definition.\n\tif attr, ok := spec.Attr(\"auto_increment\"); ok {\n\t\tv, err := attr.Int64()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tt.AddAttrs(&AutoIncrement{V: v})\n\t}\n\tif attr, ok := spec.Attr(\"engine\"); ok {\n\t\tv, err := attr.String()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tt.AddAttrs(&Engine{V: v})\n\t}\n\treturn t, nil\n}\n\n// convertPK converts a sqlspec.PrimaryKey into a schema.Index.\nfunc convertPK(spec *sqlspec.PrimaryKey, parent *schema.Table) (*schema.Index, error) {\n\treturn convertIndex(&sqlspec.Index{\n\t\tParts:            spec.Parts,\n\t\tColumns:          spec.Columns,\n\t\tDefaultExtension: spec.DefaultExtension,\n\t}, parent)\n}\n\n// convertIndex converts a sqlspec.Index into a schema.Index.\nfunc convertIndex(spec *sqlspec.Index, parent *schema.Table) (*schema.Index, error) {\n\tidx, err := specutil.Index(spec, parent, convertPart)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := convertIndexType(spec, idx); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := convertIndexParser(spec, idx); err != nil {\n\t\treturn nil, err\n\t}\n\treturn idx, nil\n}\n\nfunc convertIndexType(spec specutil.Attrer, idx *schema.Index) error {\n\tif attr, ok := spec.Attr(\"type\"); ok {\n\t\tt, err := attr.String()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tidx.AddAttrs(&IndexType{T: t})\n\t}\n\treturn nil\n}\n\nfunc convertIndexParser(spec specutil.Attrer, idx *schema.Index) error {\n\tif attr, ok := spec.Attr(\"parser\"); ok {\n\t\tp, err := attr.String()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tidx.AddAttrs(&IndexParser{P: p})\n\t}\n\treturn nil\n}\n\nfunc convertPart(spec *sqlspec.IndexPart, part *schema.IndexPart) error {\n\tif attr, ok := spec.Attr(\"prefix\"); ok {\n\t\tif part.X != nil {\n\t\t\treturn errors.New(\"attribute 'on.prefix' cannot be used in functional part\")\n\t\t}\n\t\tp, err := attr.Int()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tpart.AddAttrs(&SubPart{Len: p})\n\t}\n\treturn nil\n}\n\n// convertCheck converts a sqlspec.Check into a schema.Check.\nfunc convertCheck(spec *sqlspec.Check) (*schema.Check, error) {\n\tc, err := specutil.Check(spec)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif attr, ok := spec.Attr(\"enforced\"); ok {\n\t\tb, err := attr.Bool()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tc.AddAttrs(&Enforced{V: b})\n\t}\n\treturn c, nil\n}\n\n// convertColumn converts a sqlspec.Column into a schema.Column.\nfunc convertColumn(spec *sqlspec.Column, _ *schema.Table) (*schema.Column, error) {\n\tc, err := specutil.Column(spec, convertColumnType)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := convertCharset(spec, &c.Attrs); err != nil {\n\t\treturn nil, err\n\t}\n\tif attr, ok := spec.Attr(\"on_update\"); ok {\n\t\tx, err := attr.RawExpr()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(`unexpected type %T for attribute \"on_update\"`, attr.V.Type())\n\t\t}\n\t\tc.AddAttrs(&OnUpdate{A: x.X})\n\t}\n\tif attr, ok := spec.Attr(\"auto_increment\"); ok {\n\t\tb, err := attr.Bool()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif b {\n\t\t\tc.AddAttrs(&AutoIncrement{})\n\t\t}\n\t}\n\tif err := specutil.ConvertGenExpr(spec.Remain(), c, storedOrVirtual); err != nil {\n\t\treturn nil, err\n\t}\n\treturn c, err\n}\n\n// convertColumnType converts a sqlspec.Column into a concrete MySQL schema.Type.\nfunc convertColumnType(spec *sqlspec.Column) (schema.Type, error) {\n\treturn TypeRegistry.Type(spec.Type, spec.Extra.Attrs)\n}\n\n// schemaSpec converts from a concrete MySQL schema to Atlas specification.\nfunc schemaSpec(s *schema.Schema) (*specutil.SchemaSpec, error) {\n\tspec, err := specutil.FromSchema(s, specFuncs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif c, ok := sqlx.Charset(s.Attrs, nil); ok {\n\t\tspec.Schema.Extra.Attrs = append(spec.Schema.Extra.Attrs, schemahcl.StringAttr(\"charset\", c))\n\t}\n\tif c, ok := sqlx.Collate(s.Attrs, nil); ok {\n\t\tspec.Schema.Extra.Attrs = append(spec.Schema.Extra.Attrs, schemahcl.StringAttr(\"collate\", c))\n\t}\n\treturn spec, nil\n}\n\n// tableSpec converts from a concrete MySQL sqlspec.Table to a schema.Table.\nfunc tableSpec(t *schema.Table) (*sqlspec.Table, error) {\n\tts, err := specutil.FromTable(\n\t\tt,\n\t\tcolumnSpec,\n\t\tpkSpec,\n\t\tindexSpec,\n\t\tspecutil.FromForeignKey,\n\t\tcheckSpec,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif c, ok := sqlx.Charset(t.Attrs, t.Schema.Attrs); ok {\n\t\tts.Extra.Attrs = append(ts.Extra.Attrs, schemahcl.StringAttr(\"charset\", c))\n\t}\n\tif c, ok := sqlx.Collate(t.Attrs, t.Schema.Attrs); ok {\n\t\tts.Extra.Attrs = append(ts.Extra.Attrs, schemahcl.StringAttr(\"collate\", c))\n\t}\n\t// Marshal the engine attribute only if it is not InnoDB (default).\n\tif e := (&Engine{}); sqlx.Has(t.Attrs, e) && e.V != \"\" && !e.Default {\n\t\tattr := schemahcl.StringAttr(\"engine\", e.V)\n\t\tfor _, e1 := range []string{EngineInnoDB, EngineMyISAM, EngineMemory, EngineCSV, EngineNDB} {\n\t\t\tif strings.EqualFold(e.V, e1) {\n\t\t\t\tattr = specutil.VarAttr(\"engine\", e1)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tts.Extra.Attrs = append(ts.Extra.Attrs, attr)\n\t}\n\treturn ts, nil\n}\n\nfunc pkSpec(idx *schema.Index) (*sqlspec.PrimaryKey, error) {\n\tspec, err := indexSpec(idx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, p := range spec.Parts {\n\t\tif p.Expr != \"\" {\n\t\t\treturn nil, fmt.Errorf(\"primary key %q cannot have functional part\", idx.Name)\n\t\t}\n\t}\n\treturn &sqlspec.PrimaryKey{Parts: spec.Parts, Columns: spec.Columns, DefaultExtension: spec.DefaultExtension}, nil\n}\n\nfunc indexSpec(idx *schema.Index) (*sqlspec.Index, error) {\n\tspec, err := specutil.FromIndex(idx, partAttr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tspec.Extra.Attrs = indexTypeSpec(idx, spec.Extra.Attrs)\n\treturn spec, nil\n}\n\nfunc indexTypeSpec(idx *schema.Index, attrs []*schemahcl.Attr) []*schemahcl.Attr {\n\t// Avoid printing the index type if it is the default.\n\tif i := (IndexType{}); sqlx.Has(idx.Attrs, &i) && i.T != IndexTypeBTree {\n\t\tattrs = append(attrs, specutil.VarAttr(\"type\", strings.ToUpper(i.T)))\n\t}\n\t// Print fulltext index parser. Use the pre-defined parser variables if known.\n\tif p := (IndexParser{}); sqlx.Has(idx.Attrs, &p) && p.P != \"\" {\n\t\tattr := schemahcl.StringAttr(\"parser\", p.P)\n\t\tfor _, p1 := range []string{IndexParserNGram, IndexParserMeCab} {\n\t\t\tif strings.EqualFold(p.P, p1) {\n\t\t\t\tattr = specutil.VarAttr(\"parser\", p1)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tattrs = append(attrs, attr)\n\t}\n\treturn attrs\n}\n\nfunc partAttr(_ *schema.Index, part *schema.IndexPart, spec *sqlspec.IndexPart) error {\n\tif p := (SubPart{}); sqlx.Has(part.Attrs, &p) && p.Len > 0 {\n\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.IntAttr(\"prefix\", p.Len))\n\t}\n\treturn nil\n}\n\n// columnSpec converts from a concrete MySQL schema.Column into a sqlspec.Column.\nfunc columnSpec(c *schema.Column, t *schema.Table) (*sqlspec.Column, error) {\n\tspec, err := specutil.FromColumn(c, columnTypeSpec)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif c, ok := sqlx.Charset(c.Attrs, t.Attrs); ok {\n\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.StringAttr(\"charset\", c))\n\t}\n\tif c, ok := sqlx.Collate(c.Attrs, t.Attrs); ok {\n\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.StringAttr(\"collate\", c))\n\t}\n\tif o := (OnUpdate{}); sqlx.Has(c.Attrs, &o) {\n\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.RawAttr(\"on_update\", o.A))\n\t}\n\tif sqlx.Has(c.Attrs, &AutoIncrement{}) {\n\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.BoolAttr(\"auto_increment\", true))\n\t}\n\tif x := (schema.GeneratedExpr{}); sqlx.Has(c.Attrs, &x) {\n\t\tspec.Extra.Children = append(spec.Extra.Children, specutil.FromGenExpr(x, storedOrVirtual))\n\t}\n\treturn spec, nil\n}\n\n// storedOrVirtual returns a STORED or VIRTUAL\n// generated type option based on the given string.\nfunc storedOrVirtual(s string) string {\n\tswitch s = strings.ToUpper(s); s {\n\t// The default is VIRTUAL if no type is specified.\n\tcase \"\":\n\t\treturn virtual\n\t// In MariaDB, PERSISTENT is synonyms for STORED.\n\tcase persistent:\n\t\treturn stored\n\t}\n\treturn s\n}\n\n// checkSpec converts from a concrete MySQL schema.Check into a sqlspec.Check.\nfunc checkSpec(s *schema.Check) *sqlspec.Check {\n\tc := specutil.FromCheck(s)\n\tif e := (Enforced{}); sqlx.Has(s.Attrs, &e) {\n\t\tc.Extra.Attrs = append(c.Extra.Attrs, schemahcl.BoolAttr(\"enforced\", true))\n\t}\n\treturn c\n}\n\n// columnTypeSpec converts from a concrete MySQL schema.Type into sqlspec.Column Type.\nfunc columnTypeSpec(t schema.Type) (*sqlspec.Column, error) {\n\tst, err := TypeRegistry.Convert(t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc := &sqlspec.Column{Type: st}\n\tfor _, attr := range st.Attrs {\n\t\t// TODO(rotemtam): infer this from the TypeSpec\n\t\tif attr.K == \"unsigned\" {\n\t\t\tc.Extra.Attrs = append(c.Extra.Attrs, attr)\n\t\t}\n\t}\n\treturn c, nil\n}\n\n// convertCharset converts spec charset/collation\n// attributes to schema element attributes.\nfunc convertCharset(spec specutil.Attrer, attrs *[]schema.Attr) error {\n\tif attr, ok := spec.Attr(\"charset\"); ok {\n\t\ts, err := attr.String()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t*attrs = append(*attrs, &schema.Charset{V: s})\n\t}\n\t// For backwards compatibility, accepts both \"collate\" and \"collation\".\n\tattr, ok := spec.Attr(\"collate\")\n\tif !ok {\n\t\tattr, ok = spec.Attr(\"collation\")\n\t}\n\tif ok {\n\t\ts, err := attr.String()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t*attrs = append(*attrs, &schema.Collation{V: s})\n\t}\n\treturn nil\n}\n\n// TypeRegistry contains the supported TypeSpecs for the mysql driver.\nvar TypeRegistry = schemahcl.NewRegistry(\n\tschemahcl.WithFormatter(FormatType),\n\tschemahcl.WithParser(ParseType),\n\tschemahcl.WithSpecs(\n\t\t&schemahcl.TypeSpec{\n\t\t\tName: TypeEnum,\n\t\t\tT:    TypeEnum,\n\t\t\tAttributes: []*schemahcl.TypeAttr{\n\t\t\t\t{Name: \"values\", Kind: reflect.Slice, Required: true},\n\t\t\t},\n\t\t\tRType: reflect.TypeOf(schema.EnumType{}),\n\t\t\tFromSpec: func(t *schemahcl.Type) (schema.Type, error) {\n\t\t\t\tif len(t.Attrs) != 1 || t.Attrs[0].K != \"values\" {\n\t\t\t\t\treturn nil, fmt.Errorf(\"invalid enum type spec: %v\", t)\n\t\t\t\t}\n\t\t\t\tv, err := t.Attrs[0].Strings()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\treturn &schema.EnumType{T: \"enum\", Values: v}, nil\n\t\t\t},\n\t\t},\n\t\t&schemahcl.TypeSpec{\n\t\t\tName: TypeSet,\n\t\t\tT:    TypeSet,\n\t\t\tAttributes: []*schemahcl.TypeAttr{\n\t\t\t\t{Name: \"values\", Kind: reflect.Slice, Required: true},\n\t\t\t},\n\t\t\tRType: reflect.TypeOf(SetType{}),\n\t\t\tFromSpec: func(t *schemahcl.Type) (schema.Type, error) {\n\t\t\t\tif len(t.Attrs) != 1 || t.Attrs[0].K != \"values\" {\n\t\t\t\t\treturn nil, fmt.Errorf(\"invalid set type spec: %v\", t)\n\t\t\t\t}\n\t\t\t\tv, err := t.Attrs[0].Strings()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\treturn &SetType{Values: v}, nil\n\t\t\t},\n\t\t},\n\t\tschemahcl.NewTypeSpec(TypeBool),\n\t\tschemahcl.NewTypeSpec(TypeBoolean),\n\t\tschemahcl.NewTypeSpec(TypeBit, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeInt, schemahcl.WithAttributes(unsignedTypeAttr(), schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeTinyInt, schemahcl.WithAttributes(unsignedTypeAttr(), schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeSmallInt, schemahcl.WithAttributes(unsignedTypeAttr(), schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeMediumInt, schemahcl.WithAttributes(unsignedTypeAttr(), schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeBigInt, schemahcl.WithAttributes(unsignedTypeAttr(), schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeDecimal, schemahcl.WithAttributes(unsignedTypeAttr(), schemahcl.PrecisionTypeAttr(), schemahcl.ScaleTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeNumeric, schemahcl.WithAttributes(unsignedTypeAttr(), schemahcl.PrecisionTypeAttr(), schemahcl.ScaleTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeFloat, schemahcl.WithAttributes(unsignedTypeAttr(), schemahcl.PrecisionTypeAttr(), schemahcl.ScaleTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeDouble, schemahcl.WithAttributes(unsignedTypeAttr(), schemahcl.PrecisionTypeAttr(), schemahcl.ScaleTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeReal, schemahcl.WithAttributes(unsignedTypeAttr(), schemahcl.PrecisionTypeAttr(), schemahcl.ScaleTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeTimestamp, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeDate),\n\t\tschemahcl.NewTypeSpec(TypeTime, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeDateTime, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeYear, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeVarchar, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(true))),\n\t\tschemahcl.NewTypeSpec(TypeChar, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeVarBinary, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(true))),\n\t\tschemahcl.NewTypeSpec(TypeBinary, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeBlob, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeTinyBlob),\n\t\tschemahcl.NewTypeSpec(TypeMediumBlob),\n\t\tschemahcl.NewTypeSpec(TypeLongBlob),\n\t\tschemahcl.NewTypeSpec(TypeJSON),\n\t\tschemahcl.NewTypeSpec(TypeText, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeTinyText),\n\t\tschemahcl.NewTypeSpec(TypeMediumText),\n\t\tschemahcl.NewTypeSpec(TypeLongText),\n\t\tschemahcl.NewTypeSpec(TypeGeometry),\n\t\tschemahcl.NewTypeSpec(TypePoint),\n\t\tschemahcl.NewTypeSpec(TypeMultiPoint),\n\t\tschemahcl.NewTypeSpec(TypeLineString),\n\t\tschemahcl.NewTypeSpec(TypeMultiLineString),\n\t\tschemahcl.NewTypeSpec(TypePolygon),\n\t\tschemahcl.NewTypeSpec(TypeMultiPolygon),\n\t\tschemahcl.NewTypeSpec(TypeGeometryCollection),\n\t\tschemahcl.NewTypeSpec(TypeInet4),\n\t\tschemahcl.NewTypeSpec(TypeInet6),\n\t),\n)\n\nfunc unsignedTypeAttr() *schemahcl.TypeAttr {\n\treturn &schemahcl.TypeAttr{\n\t\tName: \"unsigned\",\n\t\tKind: reflect.Bool,\n\t}\n}\n"
  },
  {
    "path": "sql/mysql/sqlspec_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage mysql\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/internal/spectest\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSQLSpec(t *testing.T) {\n\tf := `table \"table\" {\n  schema  = schema.schema\n  comment = \"table comment\"\n  auto_increment = 1000\n  column \"col\" {\n    null    = false\n    type    = int\n    comment = \"column comment\"\n  }\n  column \"age\" {\n    null = false\n    type = int\n  }\n  column \"price1\" {\n    null = false\n    type = int\n  }\n  column \"price2\" {\n    null           = false\n    type           = int\n    auto_increment = true\n  }\n  column \"account_name\" {\n    null    = false\n    type    = varchar(32)\n    default = \"unknown\"\n  }\n  column \"account_type\" {\n    null    = false\n    type    = enum(\"FREE\",\"PRO\")\n    default = \"FREE\"\n  }\n  column \"created_at\" {\n    null    = false\n    type    = datetime(4)\n    default = sql(\"now(4)\")\n  }\n  column \"updated_at\" {\n    null      = false\n    type      = timestamp(6)\n    default   = sql(\"current_timestamp(6)\")\n    on_update = sql(\"current_timestamp(6)\")\n  }\n  primary_key {\n    columns = [column.col]\n  }\n  foreign_key \"accounts\" {\n    columns     = [column.account_name]\n    ref_columns = [table.accounts.column.name]\n    on_delete   = SET_NULL\n  }\n  index \"index\" {\n    unique  = true\n    columns = [column.col, column.age]\n    comment = \"index comment\"\n  }\n  check \"positive price\" {\n    expr     = \"price1 > 0\"\n    enforced = false\n  }\n  check {\n    expr = \"price1 <> price2\"\n  }\n  check \"named\" {\n    expr = \"price2 > price1\"\n  }\n}\n\ntable \"accounts\" {\n  schema = schema.schema\n  column \"name\" {\n    null = false\n    type = varchar(32)\n  }\n  column \"unsigned_float\" {\n    null     = false\n    type     = float(10)\n    unsigned = true\n  }\n  column \"unsigned_decimal\" {\n    null     = false\n    type     = decimal(10,2)\n    unsigned = true\n  }\n  primary_key {\n    columns = [column.name]\n  }\n}\nschema \"schema\" {\n}\n`\n\tvar s schema.Schema\n\terr := EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\n\texp := schema.NewRealm(schema.New(\"schema\")).Schemas[0]\n\texp.Tables = []*schema.Table{\n\t\t{\n\t\t\tName:   \"table\",\n\t\t\tSchema: exp,\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{\n\t\t\t\t\tName: \"col\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\t\tT: TypeInt,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t&schema.Comment{Text: \"column comment\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"age\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\t\tT: TypeInt,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"price1\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\t\tT: TypeInt,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"price2\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\t\tT: TypeInt,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAttrs: []schema.Attr{&AutoIncrement{}},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"account_name\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.StringType{\n\t\t\t\t\t\t\tT:    TypeVarchar,\n\t\t\t\t\t\t\tSize: 32,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"unknown\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"account_type\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.EnumType{\n\t\t\t\t\t\t\tT:      TypeEnum,\n\t\t\t\t\t\t\tValues: []string{\"FREE\", \"PRO\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tDefault: &schema.Literal{\n\t\t\t\t\t\tV: \"FREE\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"created_at\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: typeTime(TypeDateTime, 4),\n\t\t\t\t\t},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"now(4)\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"updated_at\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: typeTime(TypeTimestamp, 6),\n\t\t\t\t\t},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"current_timestamp(6)\"},\n\t\t\t\t\tAttrs:   []schema.Attr{&OnUpdate{A: \"current_timestamp(6)\"}},\n\t\t\t\t},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Check{\n\t\t\t\t\tName:  \"positive price\",\n\t\t\t\t\tExpr:  \"price1 > 0\",\n\t\t\t\t\tAttrs: []schema.Attr{&Enforced{V: false}},\n\t\t\t\t},\n\t\t\t\t&schema.Check{\n\t\t\t\t\tExpr: \"price1 <> price2\",\n\t\t\t\t},\n\t\t\t\t&schema.Check{\n\t\t\t\t\tName: \"named\",\n\t\t\t\t\tExpr: \"price2 > price1\",\n\t\t\t\t},\n\t\t\t\t&schema.Comment{Text: \"table comment\"},\n\t\t\t\t&AutoIncrement{V: 1000},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:   \"accounts\",\n\t\t\tSchema: exp,\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{\n\t\t\t\t\tName: \"name\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.StringType{\n\t\t\t\t\t\t\tT:    TypeVarchar,\n\t\t\t\t\t\t\tSize: 32,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"unsigned_float\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.FloatType{\n\t\t\t\t\t\t\tT:         TypeFloat,\n\t\t\t\t\t\t\tPrecision: 10,\n\t\t\t\t\t\t\tUnsigned:  true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"unsigned_decimal\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.DecimalType{\n\t\t\t\t\t\t\tT:         TypeDecimal,\n\t\t\t\t\t\t\tPrecision: 10,\n\t\t\t\t\t\t\tScale:     2,\n\t\t\t\t\t\t\tUnsigned:  true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\texp.Tables[0].PrimaryKey = &schema.Index{\n\t\tTable: exp.Tables[0],\n\t\tParts: []*schema.IndexPart{\n\t\t\t{SeqNo: 0, C: exp.Tables[0].Columns[0]},\n\t\t},\n\t}\n\texp.Tables[0].Indexes = []*schema.Index{\n\t\t{\n\t\t\tName:   \"index\",\n\t\t\tTable:  exp.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: exp.Tables[0].Columns[0]},\n\t\t\t\t{SeqNo: 1, C: exp.Tables[0].Columns[1]},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Comment{Text: \"index comment\"},\n\t\t\t},\n\t\t},\n\t}\n\texp.Tables[0].ForeignKeys = []*schema.ForeignKey{\n\t\t{\n\t\t\tSymbol:     \"accounts\",\n\t\t\tTable:      exp.Tables[0],\n\t\t\tColumns:    []*schema.Column{exp.Tables[0].Columns[4]},\n\t\t\tRefTable:   exp.Tables[1],\n\t\t\tRefColumns: []*schema.Column{exp.Tables[1].Columns[0]},\n\t\t\tOnDelete:   schema.SetNull,\n\t\t},\n\t}\n\texp.Tables[1].PrimaryKey = &schema.Index{\n\t\tTable: exp.Tables[1],\n\t\tParts: []*schema.IndexPart{\n\t\t\t{SeqNo: 0, C: exp.Tables[1].Columns[0]},\n\t\t},\n\t}\n\texp.Tables[0].Columns[0].AddIndexes(exp.Tables[0].PrimaryKey)\n\texp.Tables[0].Columns[0].AddIndexes(exp.Tables[0].Indexes[0])\n\texp.Tables[0].Columns[1].AddIndexes(exp.Tables[0].Indexes[0])\n\texp.Tables[1].Columns[0].AddIndexes(exp.Tables[1].PrimaryKey)\n\trequire.EqualValues(t, exp, &s)\n\t_, err = MarshalHCL(&s)\n\trequire.NoError(t, err)\n}\n\nfunc TestMarshalSpec_Charset(t *testing.T) {\n\ts := &schema.Schema{\n\t\tName: \"test\",\n\t\tAttrs: []schema.Attr{\n\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t&schema.Collation{V: \"utf8mb4_0900_ai_ci\"},\n\t\t},\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t\t&schema.Collation{V: \"utf8mb4_0900_ai_ci\"},\n\t\t\t\t},\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"a\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"b\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"utf8mb4_0900_ai_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"posts\",\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t},\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"a\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"b\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t\t\t\t\t&schema.Collation{V: \"utf8mb4_0900_ai_ci\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\ts.Tables[0].Schema = s\n\ts.Tables[1].Schema = s\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\t// Charset and collate that are identical to their parent elements\n\t// should not be printed as they are inherited by default from it.\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"a\" {\n    null    = false\n    type    = text\n    charset = \"latin1\"\n    collate = \"latin1_swedish_ci\"\n  }\n  column \"b\" {\n    null = false\n    type = text\n  }\n}\ntable \"posts\" {\n  schema  = schema.test\n  charset = \"latin1\"\n  collate = \"latin1_swedish_ci\"\n  column \"a\" {\n    null = false\n    type = text\n  }\n  column \"b\" {\n    null    = false\n    type    = text\n    charset = \"utf8mb4\"\n    collate = \"utf8mb4_0900_ai_ci\"\n  }\n}\nschema \"test\" {\n  charset = \"utf8mb4\"\n  collate = \"utf8mb4_0900_ai_ci\"\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n\n\tvar (\n\t\ts2    schema.Schema\n\t\tlatin = []schema.Attr{\n\t\t\t&schema.Charset{V: \"latin1\"},\n\t\t\t&schema.Collation{V: \"latin1_swedish_ci\"},\n\t\t}\n\t\tutf8mb4 = []schema.Attr{\n\t\t\t&schema.Charset{V: \"utf8mb4\"},\n\t\t\t&schema.Collation{V: \"utf8mb4_0900_ai_ci\"},\n\t\t}\n\t)\n\trequire.NoError(t, EvalHCLBytes(buf, &s2, nil))\n\trequire.Equal(t, utf8mb4, s2.Attrs)\n\tposts, ok := s2.Table(\"posts\")\n\trequire.True(t, ok)\n\trequire.Equal(t, latin, posts.Attrs)\n\tusers, ok := s2.Table(\"users\")\n\trequire.True(t, ok)\n\trequire.Empty(t, users.Attrs)\n\ta, ok := users.Column(\"a\")\n\trequire.True(t, ok)\n\trequire.Equal(t, latin, a.Attrs)\n\tb, ok := posts.Column(\"b\")\n\trequire.True(t, ok)\n\trequire.Equal(t, utf8mb4, b.Attrs)\n}\n\nfunc TestMarshalSpec_Comment(t *testing.T) {\n\ts := &schema.Schema{\n\t\tName: \"test\",\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Comment{Text: \"table comment\"},\n\t\t\t\t},\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"a\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Comment{Text: \"column comment\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName: \"posts\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"a\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\ts.Tables[0].Schema = s\n\ts.Tables[1].Schema = s\n\ts.Tables[0].Indexes = []*schema.Index{\n\t\t{\n\t\t\tName:   \"index\",\n\t\t\tTable:  s.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts:  []*schema.IndexPart{{SeqNo: 0, C: s.Tables[0].Columns[0]}},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Comment{Text: \"index comment\"},\n\t\t\t},\n\t\t},\n\t}\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\t// We expect a zero value comment to not be present in the marshaled HCL.\n\tconst expected = `table \"users\" {\n  schema  = schema.test\n  comment = \"table comment\"\n  column \"a\" {\n    null    = false\n    type    = text\n    comment = \"column comment\"\n  }\n  index \"index\" {\n    unique  = true\n    columns = [column.a]\n    comment = \"index comment\"\n  }\n}\ntable \"posts\" {\n  schema = schema.test\n  column \"a\" {\n    null = false\n    type = text\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_AutoIncrement(t *testing.T) {\n\ts := &schema.Schema{\n\t\tName: \"test\",\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"id\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&AutoIncrement{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\ts.Tables[0].Schema = s\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"id\" {\n    null           = false\n    type           = bigint\n    auto_increment = true\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_Check(t *testing.T) {\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"products\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"price1\", TypeInt),\n\t\t\t\t\tschema.NewIntColumn(\"price2\", TypeInt),\n\t\t\t\t).\n\t\t\t\tAddChecks(\n\t\t\t\t\tschema.NewCheck().SetName(\"price1 positive\").SetExpr(\"price1 > 0\"),\n\t\t\t\t\tschema.NewCheck().SetExpr(\"price1 <> price2\").AddAttrs(&Enforced{}),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"products\" {\n  schema = schema.test\n  column \"price1\" {\n    null = false\n    type = int\n  }\n  column \"price2\" {\n    null = false\n    type = int\n  }\n  check \"price1 positive\" {\n    expr = \"price1 > 0\"\n  }\n  check {\n    expr     = \"price1 <> price2\"\n    enforced = true\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_TableEngine(t *testing.T) {\n\ts := schema.New(\"a8m\").\n\t\tAddTables(\n\t\t\t// InnoDB (default) is not printed.\n\t\t\tschema.NewTable(\"repos\").AddAttrs(&Engine{V: EngineInnoDB, Default: true}).AddColumns(schema.NewIntColumn(\"id\", TypeBigInt)),\n\t\t\tschema.NewTable(\"stars\").AddAttrs(&Engine{V: \"INNODB\", Default: true}).AddColumns(schema.NewIntColumn(\"id\", TypeBigInt)),\n\t\t\tschema.NewTable(\"prs\").AddAttrs(&Engine{V: EngineMyISAM}).AddColumns(schema.NewIntColumn(\"id\", TypeBigInt)),\n\t\t\tschema.NewTable(\"issues\").AddAttrs(&Engine{V: \"MYISAM\"}).AddColumns(schema.NewIntColumn(\"id\", TypeBigInt)),\n\t\t\tschema.NewTable(\"commits\").AddAttrs(&Engine{V: \"MyRocks\"}).AddColumns(schema.NewIntColumn(\"id\", TypeBigInt)),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"repos\" {\n  schema = schema.a8m\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n}\ntable \"stars\" {\n  schema = schema.a8m\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n}\ntable \"prs\" {\n  schema = schema.a8m\n  engine = MyISAM\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n}\ntable \"issues\" {\n  schema = schema.a8m\n  engine = MyISAM\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n}\ntable \"commits\" {\n  schema = schema.a8m\n  engine = \"MyRocks\"\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n}\nschema \"a8m\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestUnmarshalSpec_TableEngine(t *testing.T) {\n\tvar (\n\t\ts schema.Schema\n\t\tf = `table \"repos\" {\n  schema = schema.a8m\n  engine = InnoDB\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n}\ntable \"stars\" {\n  schema = schema.a8m\n  engine = \"INNODB\"\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n}\ntable \"prs\" {\n  schema = schema.a8m\n  engine = MyISAM\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n}\ntable \"issues\" {\n  schema = schema.a8m\n  engine = \"MYISAM\"\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n}\ntable \"commits\" {\n  schema = schema.a8m\n  engine = \"MyRocks\"\n  column \"id\" {\n    null = false\n    type = bigint\n  }\n}\nschema \"a8m\" {}\n`\n\t)\n\trequire.NoError(t, EvalHCLBytes([]byte(f), &s, nil))\n\tfor i, e := range []string{EngineInnoDB, \"INNODB\", EngineMyISAM, \"MYISAM\", \"MyRocks\"} {\n\t\trequire.EqualValues(t, e, s.Tables[i].Attrs[0].(*Engine).V)\n\t}\n}\n\nfunc TestUnmarshalSpec_IndexParts(t *testing.T) {\n\tvar (\n\t\ts schema.Schema\n\t\tf = `\nschema \"test\" {}\ntable \"users\" {\n\tschema = schema.test\n\tcolumn \"name\" {\n\t\ttype = text\n\t}\n\tindex \"idx\" {\n\t\ton {\n\t\t\tcolumn = table.users.column.name\n\t\t\tdesc = true\n\t\t\tprefix = 10\n\t\t}\n\t\ton {\n\t\t\texpr = \"lower(name)\"\n\t\t}\n\t}\n}\n`\n\t)\n\terr := EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\tc := schema.NewStringColumn(\"name\", \"text\")\n\texp := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(c).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewIndex(\"idx\").\n\t\t\t\t\t\tAddParts(\n\t\t\t\t\t\t\tschema.NewColumnPart(c).SetDesc(true).AddAttrs(&SubPart{Len: 10}),\n\t\t\t\t\t\t\tschema.NewExprPart(&schema.RawExpr{X: \"lower(name)\"}),\n\t\t\t\t\t\t),\n\t\t\t\t),\n\t\t)\n\tschema.NewRealm(exp)\n\trequire.EqualValues(t, exp, &s)\n}\n\nfunc TestMarshalSpec_IndexParser(t *testing.T) {\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewStringColumn(\"id\", \"text\"),\n\t\t\t\t).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewIndex(\"idx1\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewStringColumn(\"id\", \"text\"),\n\t\t\t\t\t\t).\n\t\t\t\t\t\tAddAttrs(&IndexType{T: IndexTypeFullText}, &IndexParser{P: IndexParserNGram}),\n\t\t\t\t\tschema.NewIndex(\"idx2\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewStringColumn(\"id\", \"text\"),\n\t\t\t\t\t\t).\n\t\t\t\t\t\tAddAttrs(&IndexType{T: IndexTypeFullText}, &IndexParser{P: \"custom\"}),\n\t\t\t\t),\n\t\t)\n\ts.Tables[0].SetPrimaryKey(\n\t\tschema.NewPrimaryKey(s.Tables[0].Columns...).\n\t\t\tAddAttrs(&IndexType{T: IndexTypeHash}),\n\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `table \"users\" {\n  schema = schema.test\n  column \"id\" {\n    null = false\n    type = text\n  }\n  primary_key {\n    columns = [column.id]\n    type    = HASH\n  }\n  index \"idx1\" {\n    columns = [column.id]\n    type    = FULLTEXT\n    parser  = ngram\n  }\n  index \"idx2\" {\n    columns = [column.id]\n    type    = FULLTEXT\n    parser  = \"custom\"\n  }\n}\nschema \"test\" {\n}\n`, string(buf))\n}\n\nfunc TestUnmarshalSpec_IndexParser(t *testing.T) {\n\tvar s schema.Schema\n\terr := EvalHCLBytes([]byte(`table \"users\" {\n  schema = schema.test\n  column \"id\" {\n    null = false\n    type = text\n  }\n  index \"idx1\" {\n    columns = [column.id]\n    type    = FULLTEXT\n    parser  = ngram\n  }\n  index \"idx2\" {\n    columns = [column.id]\n    type    = FULLTEXT\n    parser  = \"custom\"\n  }\n}\nschema \"test\" {\n}`), &s, nil)\n\trequire.NoError(t, err)\n\tc := schema.NewStringColumn(\"id\", \"text\")\n\texp := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(c).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewIndex(\"idx1\").\n\t\t\t\t\t\tAddColumns(c).\n\t\t\t\t\t\tAddAttrs(&IndexType{T: IndexTypeFullText}, &IndexParser{P: IndexParserNGram}),\n\t\t\t\t\tschema.NewIndex(\"idx2\").\n\t\t\t\t\t\tAddColumns(c).\n\t\t\t\t\t\tAddAttrs(&IndexType{T: IndexTypeFullText}, &IndexParser{P: \"custom\"}),\n\t\t\t\t),\n\t\t)\n\tschema.NewRealm(exp)\n\trequire.EqualValues(t, exp, &s)\n}\n\nfunc TestMarshalSpec_PrimaryKeyType(t *testing.T) {\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewStringColumn(\"id\", \"varchar(255)\"),\n\t\t\t\t),\n\t\t)\n\ts.Tables[0].SetPrimaryKey(\n\t\tschema.NewPrimaryKey(s.Tables[0].Columns...).\n\t\t\tAddAttrs(&IndexType{T: IndexTypeHash}),\n\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\texp := `table \"users\" {\n  schema = schema.test\n  column \"id\" {\n    null = false\n    type = sql(\"varchar(255)\")\n  }\n  primary_key {\n    columns = [column.id]\n    type    = HASH\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, exp, string(buf))\n}\n\nfunc TestUnmarshalSpec_PrimaryKeyType(t *testing.T) {\n\tvar s schema.Schema\n\terr := EvalHCLBytes([]byte(`table \"users\" {\n  schema = schema.test\n  column \"id\" {\n    null = false\n    type = sql(\"varchar(255)\")\n  }\n  primary_key {\n    columns = [column.id]\n    type    = HASH\n  }\n}\nschema \"test\" {\n}`), &s, nil)\n\trequire.NoError(t, err)\n\texp := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(&schema.Column{\n\t\t\t\t\tName: \"id\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.StringType{\n\t\t\t\t\t\t\tT:    \"varchar\",\n\t\t\t\t\t\t\tSize: 255,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t)\n\texp.Tables[0].SetPrimaryKey(&schema.Index{\n\t\tParts: []*schema.IndexPart{{C: exp.Tables[0].Columns[0]}},\n\t\tAttrs: []schema.Attr{&IndexType{T: IndexTypeHash}},\n\t})\n\texp.Tables[0].Columns[0].AddIndexes(exp.Tables[0].PrimaryKey)\n\tschema.NewRealm(exp)\n\trequire.EqualValues(t, exp, &s)\n}\n\nfunc TestMarshalSpec_IndexParts(t *testing.T) {\n\tc := schema.NewStringColumn(\"name\", \"text\")\n\tc2 := schema.NewStringColumn(\"Full Name\", \"text\")\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(c, c2).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewIndex(\"idx\").\n\t\t\t\t\t\tAddParts(\n\t\t\t\t\t\t\tschema.NewColumnPart(c).SetDesc(true).AddAttrs(&SubPart{Len: 10}),\n\t\t\t\t\t\t\tschema.NewExprPart(&schema.RawExpr{X: \"lower(name)\"}),\n\t\t\t\t\t\t),\n\t\t\t\t\tschema.NewIndex(\"idx2\").\n\t\t\t\t\t\tAddParts(\n\t\t\t\t\t\t\tschema.NewColumnPart(c2).SetDesc(true).AddAttrs(&SubPart{Len: 10}),\n\t\t\t\t\t\t),\n\t\t\t\t\tschema.NewIndex(\"idx3\").\n\t\t\t\t\t\tAddParts(schema.NewColumnPart(c2)),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\texp := `table \"users\" {\n  schema = schema.test\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"Full Name\" {\n    null = false\n    type = text\n  }\n  index \"idx\" {\n    on {\n      desc   = true\n      column = column.name\n      prefix = 10\n    }\n    on {\n      expr = \"lower(name)\"\n    }\n  }\n  index \"idx2\" {\n    on {\n      desc   = true\n      column = column[\"Full Name\"]\n      prefix = 10\n    }\n  }\n  index \"idx3\" {\n    columns = [column[\"Full Name\"]]\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, exp, string(buf))\n\n\t// Columns only.\n\ts = schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(c, c2).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewIndex(\"idx\").\n\t\t\t\t\t\tAddParts(\n\t\t\t\t\t\t\tschema.NewColumnPart(c).AddAttrs(&SubPart{Len: 10}),\n\t\t\t\t\t\t),\n\t\t\t\t),\n\t\t)\n\tbuf, err = MarshalHCL(s)\n\trequire.NoError(t, err)\n\texp = `table \"users\" {\n  schema = schema.test\n  column \"name\" {\n    null = false\n    type = text\n  }\n  column \"Full Name\" {\n    null = false\n    type = text\n  }\n  index \"idx\" {\n    on {\n      column = column.name\n      prefix = 10\n    }\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, exp, string(buf))\n}\n\nfunc TestMarshalSpec_TimePrecision(t *testing.T) {\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"times\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewTimeColumn(\"tTimeDef\", TypeTime),\n\t\t\t\t\tschema.NewTimeColumn(\"tTime\", TypeTime, schema.TimePrecision(1)),\n\t\t\t\t\tschema.NewTimeColumn(\"tDatetime\", TypeDateTime, schema.TimePrecision(2)),\n\t\t\t\t\tschema.NewTimeColumn(\"tTimestamp\", TypeTimestamp, schema.TimePrecision(3)).\n\t\t\t\t\t\tSetDefault(&schema.RawExpr{X: \"current_timestamp(3)\"}).\n\t\t\t\t\t\tAddAttrs(&OnUpdate{A: \"current_timestamp(3)\"}),\n\t\t\t\t\tschema.NewTimeColumn(\"tDate\", TypeDate),\n\t\t\t\t\tschema.NewTimeColumn(\"tYear\", TypeYear, schema.TimePrecision(2)),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"times\" {\n  schema = schema.test\n  column \"tTimeDef\" {\n    null = false\n    type = time\n  }\n  column \"tTime\" {\n    null = false\n    type = time(1)\n  }\n  column \"tDatetime\" {\n    null = false\n    type = datetime(2)\n  }\n  column \"tTimestamp\" {\n    null      = false\n    type      = timestamp(3)\n    default   = sql(\"current_timestamp(3)\")\n    on_update = sql(\"current_timestamp(3)\")\n  }\n  column \"tDate\" {\n    null = false\n    type = date\n  }\n  column \"tYear\" {\n    null = false\n    type = year(2)\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_GeneratedColumn(t *testing.T) {\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"c2\", \"int\").\n\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"c1 * 2\"}),\n\t\t\t\t\tschema.NewIntColumn(\"c3\", \"int\").\n\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"c2 * c3\", Type: \"VIRTUAL\"}),\n\t\t\t\t\tschema.NewIntColumn(\"c4\", \"int\").\n\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"c3 * c4\", Type: \"STORED\"}),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"c1\" {\n    null = false\n    type = int\n  }\n  column \"c2\" {\n    null = false\n    type = int\n    as {\n      expr = \"c1 * 2\"\n      type = VIRTUAL\n    }\n  }\n  column \"c3\" {\n    null = false\n    type = int\n    as {\n      expr = \"c2 * c3\"\n      type = VIRTUAL\n    }\n  }\n  column \"c4\" {\n    null = false\n    type = int\n    as {\n      expr = \"c3 * c4\"\n      type = STORED\n    }\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestUnmarshalSpec_GeneratedColumns(t *testing.T) {\n\tvar (\n\t\ts schema.Schema\n\t\tf = `\nschema \"test\" {}\ntable \"users\" {\n\tschema = schema.test\n\tcolumn \"c1\" {\n\t\ttype = int\n\t}\n\tcolumn \"c2\" {\n\t\ttype = int\n\t\tas = \"c1 * 2\"\n\t}\n\tcolumn \"c3\" {\n\t\ttype = int\n\t\tas {\n\t\t\texpr = \"c2 * 2\"\n\t\t}\n\t}\n\tcolumn \"c4\" {\n\t\ttype = int\n\t\tas {\n\t\t\texpr = \"c3 * 2\"\n\t\t\ttype = STORED\n\t\t}\n\t}\n}\n`\n\t)\n\terr := EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\texp := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"c2\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"c1 * 2\", Type: \"VIRTUAL\"}),\n\t\t\t\t\tschema.NewIntColumn(\"c3\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"c2 * 2\", Type: \"VIRTUAL\"}),\n\t\t\t\t\tschema.NewIntColumn(\"c4\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"c3 * 2\", Type: \"STORED\"}),\n\t\t\t\t),\n\t\t)\n\tschema.NewRealm(exp)\n\trequire.EqualValues(t, exp, &s)\n}\n\nfunc TestMarshalSpec_FloatUnsigned(t *testing.T) {\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"test\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewFloatColumn(\n\t\t\t\t\t\t\"float_col\",\n\t\t\t\t\t\tTypeFloat,\n\t\t\t\t\t\tschema.FloatPrecision(10),\n\t\t\t\t\t\tschema.FloatUnsigned(true),\n\t\t\t\t\t),\n\t\t\t\t\tschema.NewDecimalColumn(\n\t\t\t\t\t\t\"decimal_col\",\n\t\t\t\t\t\tTypeDecimal,\n\t\t\t\t\t\tschema.DecimalPrecision(10),\n\t\t\t\t\t\tschema.DecimalScale(2),\n\t\t\t\t\t\tschema.DecimalUnsigned(true),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"test\" {\n  schema = schema.test\n  column \"float_col\" {\n    null     = false\n    type     = float(10)\n    unsigned = true\n  }\n  column \"decimal_col\" {\n    null     = false\n    type     = decimal(10,2)\n    unsigned = true\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestTypes(t *testing.T) {\n\tp := func(i int) *int { return &i }\n\ttests := []struct {\n\t\ttypeExpr  string\n\t\textraAttr string\n\t\texpected  schema.Type\n\t}{\n\t\t{\n\t\t\ttypeExpr: \"varchar(255)\",\n\t\t\texpected: &schema.StringType{T: TypeVarchar, Size: 255},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"char(255)\",\n\t\t\texpected: &schema.StringType{T: TypeChar, Size: 255},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"custom\")`,\n\t\t\texpected: &schema.UnsupportedType{T: \"custom\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"binary(255)\",\n\t\t\texpected: &schema.BinaryType{T: TypeBinary, Size: p(255)},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"varbinary(255)\",\n\t\t\texpected: &schema.BinaryType{T: TypeVarBinary, Size: p(255)},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int\",\n\t\t\texpected: &schema.IntegerType{T: TypeInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr:  \"int\",\n\t\t\textraAttr: \"unsigned=true\",\n\t\t\texpected:  &schema.IntegerType{T: TypeInt, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int\",\n\t\t\texpected: &schema.IntegerType{T: TypeInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bigint\",\n\t\t\texpected: &schema.IntegerType{T: TypeBigInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr:  \"bigint\",\n\t\t\textraAttr: \"unsigned=true\",\n\t\t\texpected:  &schema.IntegerType{T: TypeBigInt, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tinyint\",\n\t\t\texpected: &schema.IntegerType{T: TypeTinyInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr:  \"tinyint\",\n\t\t\textraAttr: \"unsigned=true\",\n\t\t\texpected:  &schema.IntegerType{T: TypeTinyInt, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"smallint\",\n\t\t\texpected: &schema.IntegerType{T: TypeSmallInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr:  \"smallint\",\n\t\t\textraAttr: \"unsigned=true\",\n\t\t\texpected:  &schema.IntegerType{T: TypeSmallInt, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"mediumint\",\n\t\t\texpected: &schema.IntegerType{T: TypeMediumInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr:  \"mediumint\",\n\t\t\textraAttr: \"unsigned=true\",\n\t\t\texpected:  &schema.IntegerType{T: TypeMediumInt, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tinytext\",\n\t\t\texpected: &schema.StringType{T: TypeTinyText},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"mediumtext\",\n\t\t\texpected: &schema.StringType{T: TypeMediumText},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"longtext\",\n\t\t\texpected: &schema.StringType{T: TypeLongText},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"text\",\n\t\t\texpected: &schema.StringType{T: TypeText},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `enum(\"on\",\"off\")`,\n\t\t\texpected: &schema.EnumType{T: TypeEnum, Values: []string{\"on\", \"off\"}},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bit\",\n\t\t\texpected: &BitType{T: TypeBit},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bit(10)\",\n\t\t\texpected: &BitType{T: TypeBit, Size: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int(10)\",\n\t\t\texpected: &schema.IntegerType{T: TypeInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tinyint(10)\",\n\t\t\texpected: &schema.IntegerType{T: TypeTinyInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"smallint(10)\",\n\t\t\texpected: &schema.IntegerType{T: TypeSmallInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"mediumint(10)\",\n\t\t\texpected: &schema.IntegerType{T: TypeMediumInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bigint(10)\",\n\t\t\texpected: &schema.IntegerType{T: TypeBigInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"decimal\",\n\t\t\texpected: &schema.DecimalType{T: TypeDecimal},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"decimal(10)\",\n\t\t\texpected: &schema.DecimalType{T: TypeDecimal, Precision: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"decimal(10,2)\",\n\t\t\texpected: &schema.DecimalType{T: TypeDecimal, Precision: 10, Scale: 2},\n\t\t},\n\t\t{\n\t\t\ttypeExpr:  \"decimal(10,2)\",\n\t\t\textraAttr: \"unsigned=true\",\n\t\t\texpected:  &schema.DecimalType{T: TypeDecimal, Precision: 10, Scale: 2, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"numeric\",\n\t\t\texpected: &schema.DecimalType{T: TypeNumeric},\n\t\t},\n\t\t{\n\t\t\ttypeExpr:  \"numeric\",\n\t\t\textraAttr: \"unsigned=true\",\n\t\t\texpected:  &schema.DecimalType{T: TypeNumeric, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"numeric(10)\",\n\t\t\texpected: &schema.DecimalType{T: TypeNumeric, Precision: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"numeric(10,2)\",\n\t\t\texpected: &schema.DecimalType{T: TypeNumeric, Precision: 10, Scale: 2},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"float(10,0)\",\n\t\t\texpected: &schema.FloatType{T: TypeFloat, Precision: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr:  \"float(10)\",\n\t\t\textraAttr: \"unsigned=true\",\n\t\t\texpected:  &schema.FloatType{T: TypeFloat, Precision: 10, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"double(10,0)\",\n\t\t\texpected: &schema.FloatType{T: TypeDouble, Precision: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"real\",\n\t\t\texpected: &schema.FloatType{T: TypeReal},\n\t\t},\n\t\t{\n\t\t\ttypeExpr:  \"real\",\n\t\t\textraAttr: \"unsigned=true\",\n\t\t\texpected:  &schema.FloatType{T: TypeReal, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"timestamp\",\n\t\t\texpected: &schema.TimeType{T: TypeTimestamp},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"timestamp(6)\",\n\t\t\texpected: typeTime(TypeTimestamp, 6),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"date\",\n\t\t\texpected: &schema.TimeType{T: TypeDate},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"time\",\n\t\t\texpected: &schema.TimeType{T: TypeTime},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"time(6)\",\n\t\t\texpected: typeTime(TypeTime, 6),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"datetime\",\n\t\t\texpected: &schema.TimeType{T: TypeDateTime},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"datetime(6)\",\n\t\t\texpected: typeTime(TypeDateTime, 6),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"year\",\n\t\t\texpected: &schema.TimeType{T: TypeYear},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"year(2)\",\n\t\t\texpected: typeTime(TypeYear, 2),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"varchar(10)\",\n\t\t\texpected: &schema.StringType{T: TypeVarchar, Size: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"char(25)\",\n\t\t\texpected: &schema.StringType{T: TypeChar, Size: 25},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"varbinary(30)\",\n\t\t\texpected: &schema.BinaryType{T: TypeVarBinary, Size: p(30)},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"binary\",\n\t\t\texpected: &schema.BinaryType{T: TypeBinary},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"binary(5)\",\n\t\t\texpected: &schema.BinaryType{T: TypeBinary, Size: p(5)},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"blob(5)\",\n\t\t\texpected: &schema.BinaryType{T: TypeBlob},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tinyblob\",\n\t\t\texpected: &schema.BinaryType{T: TypeTinyBlob},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"mediumblob\",\n\t\t\texpected: &schema.BinaryType{T: TypeMediumBlob},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"longblob\",\n\t\t\texpected: &schema.BinaryType{T: TypeLongBlob},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"json\",\n\t\t\texpected: &schema.JSONType{T: TypeJSON},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"text(13)\",\n\t\t\texpected: &schema.StringType{T: TypeText},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tinytext\",\n\t\t\texpected: &schema.StringType{T: TypeTinyText},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"mediumtext\",\n\t\t\texpected: &schema.StringType{T: TypeMediumText},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"longtext\",\n\t\t\texpected: &schema.StringType{T: TypeLongText},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `set(\"a\",\"b\")`,\n\t\t\texpected: &SetType{Values: []string{\"a\", \"b\"}},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"geometry\",\n\t\t\texpected: &schema.SpatialType{T: TypeGeometry},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"point\",\n\t\t\texpected: &schema.SpatialType{T: TypePoint},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"multipoint\",\n\t\t\texpected: &schema.SpatialType{T: TypeMultiPoint},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"linestring\",\n\t\t\texpected: &schema.SpatialType{T: TypeLineString},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"multilinestring\",\n\t\t\texpected: &schema.SpatialType{T: TypeMultiLineString},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"polygon\",\n\t\t\texpected: &schema.SpatialType{T: TypePolygon},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"multipolygon\",\n\t\t\texpected: &schema.SpatialType{T: TypeMultiPolygon},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"geometrycollection\",\n\t\t\texpected: &schema.SpatialType{T: TypeGeometryCollection},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tinyint(1)\",\n\t\t\texpected: &schema.BoolType{T: TypeBool},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bool\",\n\t\t\texpected: &schema.BoolType{T: TypeBool},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"boolean\",\n\t\t\texpected: &schema.BoolType{T: TypeBool},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"inet4\",\n\t\t\texpected: &NetworkType{T: TypeInet4},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"inet6\",\n\t\t\texpected: &NetworkType{T: TypeInet6},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.typeExpr, func(t *testing.T) {\n\t\t\tdoc := fmt.Sprintf(`table \"test\" {\n\tschema = schema.test\n\tcolumn \"test\" {\n\t\tnull = false\n\t\ttype = %s%s\n\t}\n}\nschema \"test\" {\n}\n`, tt.typeExpr, lineIfSet(tt.extraAttr))\n\t\t\tvar test schema.Schema\n\t\t\terr := EvalHCLBytes([]byte(doc), &test, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tcolspec := test.Tables[0].Columns[0]\n\t\t\trequire.EqualValues(t, tt.expected, colspec.Type.Type)\n\t\t\tspec, err := MarshalHCL(&test)\n\t\t\trequire.NoError(t, err)\n\t\t\tvar after schema.Schema\n\t\t\terr = EvalHCLBytes(spec, &after, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.EqualValues(t, tt.expected, after.Tables[0].Columns[0].Type.Type)\n\t\t})\n\t}\n}\n\nfunc TestInputVars(t *testing.T) {\n\tspectest.TestInputVars(t, EvalHCL)\n}\n\nfunc TestParseType_Decimal(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tinput   string\n\t\twantT   *schema.DecimalType\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tinput: \"decimal\",\n\t\t\twantT: &schema.DecimalType{T: TypeDecimal},\n\t\t},\n\t\t{\n\t\t\tinput: \"decimal unsigned\",\n\t\t\twantT: &schema.DecimalType{T: TypeDecimal, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\tinput: \"decimal(10)\",\n\t\t\twantT: &schema.DecimalType{T: TypeDecimal, Precision: 10},\n\t\t},\n\t\t{\n\t\t\tinput: \"decimal(10) unsigned\",\n\t\t\twantT: &schema.DecimalType{T: TypeDecimal, Precision: 10, Unsigned: true},\n\t\t},\n\t\t{\n\t\t\tinput: \"decimal(10,2)\",\n\t\t\twantT: &schema.DecimalType{T: TypeDecimal, Precision: 10, Scale: 2},\n\t\t},\n\t\t{\n\t\t\tinput: \"decimal(10, 2) unsigned\",\n\t\t\twantT: &schema.DecimalType{T: TypeDecimal, Precision: 10, Scale: 2, Unsigned: true},\n\t\t},\n\t} {\n\t\td, err := ParseType(tt.input)\n\t\trequire.Equal(t, tt.wantErr, err != nil)\n\t\trequire.Equal(t, tt.wantT, d)\n\t}\n}\n\nfunc typeTime(t string, p int) schema.Type {\n\treturn &schema.TimeType{T: t, Precision: &p}\n}\n\nfunc lineIfSet(s string) string {\n\tif s != \"\" {\n\t\treturn \"\\n\" + s\n\t}\n\treturn s\n}\n\nfunc TestUnmarshalSpec(t *testing.T) {\n\ts := []byte(`\nschema \"s1\" {}\nschema \"s2\" {}\n\ntable \"s1\" \"t1\" {\n schema  = schema.s1\n column \"id\" {\n   type = int\n }\n}\n\ntable \"s2\" \"t1\" {\n  schema  = schema.s2\n  column \"id\" {\n    type = int\n  }\n}\ntable \"s2\" \"t2\" {\n  schema  = schema.s2\n  column \"oid\" {\n    type = int\n  }\n  foreign_key \"fk\" {\n    columns = [column.oid]\n    ref_columns = [table.s2.t1.column.id]\n  }\n}\n`)\n\tvar (\n\t\tr        schema.Realm\n\t\texpected = schema.NewRealm(\n\t\t\tschema.New(\"s1\").AddTables(schema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"id\", \"int\"))),\n\t\t\tschema.New(\"s2\").AddTables(\n\t\t\t\tschema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\tschema.NewTable(\"t2\").AddColumns(schema.NewIntColumn(\"oid\", \"int\")),\n\t\t\t),\n\t\t)\n\t)\n\texpected.Schemas[1].Tables[1].AddForeignKeys(schema.NewForeignKey(\"fk\").\n\t\tAddColumns(expected.Schemas[1].Tables[1].Columns[0]).\n\t\tSetRefTable(expected.Schemas[1].Tables[0]).\n\t\tAddRefColumns(expected.Schemas[1].Tables[0].Columns[0]))\n\trequire.NoError(t, EvalHCLBytes(s, &r, nil))\n}\n\nfunc TestMarshalRealm(t *testing.T) {\n\tt1 := schema.NewTable(\"t1\").\n\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\"))\n\tt2 := schema.NewTable(\"t2\").\n\t\tSetComment(\"Qualified with s1\").\n\t\tAddColumns(schema.NewIntColumn(\"oid\", \"int\"))\n\tt2.AddForeignKeys(schema.NewForeignKey(\"oid2id\").AddColumns(t2.Columns[0]).SetRefTable(t1).AddRefColumns(t1.Columns[0]))\n\n\tt3 := schema.NewTable(\"t3\").\n\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\"))\n\tt4 := schema.NewTable(\"t2\").\n\t\tSetComment(\"Qualified with s2\").\n\t\tAddColumns(schema.NewIntColumn(\"oid\", \"int\"))\n\tt4.AddForeignKeys(schema.NewForeignKey(\"oid2id\").AddColumns(t4.Columns[0]).SetRefTable(t3).AddRefColumns(t3.Columns[0]))\n\tt5 := schema.NewTable(\"t5\").\n\t\tAddColumns(schema.NewIntColumn(\"oid\", \"int\"))\n\tt5.AddForeignKeys(schema.NewForeignKey(\"oid2id1\").AddColumns(t5.Columns[0]).SetRefTable(t1).AddRefColumns(t1.Columns[0]))\n\t// Reference is qualified with s1.\n\tt5.AddForeignKeys(schema.NewForeignKey(\"oid2id2\").AddColumns(t5.Columns[0]).SetRefTable(t2).AddRefColumns(t2.Columns[0]))\n\n\tr := schema.NewRealm(\n\t\tschema.New(\"s1\").AddTables(t1, t2),\n\t\tschema.New(\"s2\").AddTables(t3, t4, t5),\n\t)\n\tgot, err := MarshalHCL.MarshalSpec(r)\n\trequire.NoError(t, err)\n\trequire.Equal(\n\t\tt,\n\t\t`table \"t1\" {\n  schema = schema.s1\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\ntable \"s1\" \"t2\" {\n  schema  = schema.s1\n  comment = \"Qualified with s1\"\n  column \"oid\" {\n    null = false\n    type = int\n  }\n  foreign_key \"oid2id\" {\n    columns     = [column.oid]\n    ref_columns = [table.t1.column.id]\n  }\n}\ntable \"t3\" {\n  schema = schema.s2\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\ntable \"s2\" \"t2\" {\n  schema  = schema.s2\n  comment = \"Qualified with s2\"\n  column \"oid\" {\n    null = false\n    type = int\n  }\n  foreign_key \"oid2id\" {\n    columns     = [column.oid]\n    ref_columns = [table.t3.column.id]\n  }\n}\ntable \"t5\" {\n  schema = schema.s2\n  column \"oid\" {\n    null = false\n    type = int\n  }\n  foreign_key \"oid2id1\" {\n    columns     = [column.oid]\n    ref_columns = [table.t1.column.id]\n  }\n  foreign_key \"oid2id2\" {\n    columns     = [column.oid]\n    ref_columns = [table.s1.t2.column.oid]\n  }\n}\nschema \"s1\" {\n}\nschema \"s2\" {\n}\n`,\n\t\tstring(got))\n}\n\nfunc TestUnmarshalSpec_QuotedIdentifiers(t *testing.T) {\n\tvar (\n\t\tr schema.Realm\n\t\ts = []byte(`\nschema \"a8m.schema\" {}\ntable \"a8m.table\" {\n  schema = schema[\"a8m.schema\"]\n  column \"a8m.column\" {\n    type = int\n  }\n}\n\nschema \"nati.schema\" {}\ntable \"nati.schema\" \"nati.table\" {\n  schema = schema[\"nati.schema\"]\n  column \"nati.column\" {\n    type = int\n  }\n  foreign_key \"nati.fk\" {\n    columns = [column[\"nati.column\"]]\n\tref_columns = [table[\"a8m.table\"].column[\"a8m.column\"]]\n  }\n}\n`)\n\t)\n\trequire.NoError(t, EvalHCLBytes(s, &r, nil))\n\trequire.Len(t, r.Schemas, 2)\n\ts1, ok := r.Schema(\"a8m.schema\")\n\trequire.True(t, ok)\n\trequire.Equal(t, \"a8m.schema\", s1.Name)\n\trequire.Len(t, r.Schemas[0].Tables, 1)\n\trequire.Equal(t, \"a8m.table\", s1.Tables[0].Name)\n\trequire.Len(t, r.Schemas[0].Tables[0].Columns, 1)\n\trequire.Equal(t, \"a8m.column\", s1.Tables[0].Columns[0].Name)\n\ts2, ok := r.Schema(\"nati.schema\")\n\trequire.True(t, ok)\n\trequire.Equal(t, \"nati.schema\", s2.Name)\n\trequire.Len(t, r.Schemas[1].Tables, 1)\n\trequire.Equal(t, \"nati.table\", s2.Tables[0].Name)\n\trequire.Len(t, r.Schemas[1].Tables[0].Columns, 1)\n\trequire.Equal(t, \"nati.column\", s2.Tables[0].Columns[0].Name)\n\trequire.Len(t, r.Schemas[1].Tables[0].ForeignKeys, 1)\n\trequire.Equal(t, \"nati.fk\", s2.Tables[0].ForeignKeys[0].Symbol)\n\trequire.Len(t, r.Schemas[1].Tables[0].ForeignKeys[0].Columns, 1)\n\trequire.Equal(t, \"nati.column\", s2.Tables[0].ForeignKeys[0].Columns[0].Name)\n\trequire.Len(t, r.Schemas[1].Tables[0].ForeignKeys[0].RefColumns, 1)\n\trequire.Equal(t, \"a8m.column\", s2.Tables[0].ForeignKeys[0].RefColumns[0].Name)\n}\n\nfunc TestMarshalSpec_QuotedIdentifiers(t *testing.T) {\n\ts1 := schema.New(\"a8m.schema\").\n\t\tAddTables(schema.NewTable(\"a8m.table\").\n\t\t\tAddColumns(schema.NewIntColumn(\"a8m.column\", \"int\")))\n\ts2 := schema.New(\"nati.schema\").\n\t\tAddTables(schema.NewTable(\"nati.table\").\n\t\t\tAddColumns(schema.NewIntColumn(\"nati.column\", \"int\")).\n\t\t\tAddForeignKeys(schema.NewForeignKey(\"nati.fk\").\n\t\t\t\tAddColumns(s1.Tables[0].Columns[0]).\n\t\t\t\tSetRefTable(s1.Tables[0]).\n\t\t\t\tAddRefColumns(s1.Tables[0].Columns[0])))\n\tr := schema.NewRealm(s1, s2)\n\tgot, err := MarshalHCL.MarshalSpec(r)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `table \"a8m.table\" {\n  schema = schema[\"a8m.schema\"]\n  column \"a8m.column\" {\n    null = false\n    type = int\n  }\n}\ntable \"nati.table\" {\n  schema = schema[\"nati.schema\"]\n  column \"nati.column\" {\n    null = false\n    type = int\n  }\n  foreign_key \"nati.fk\" {\n    columns     = [column[\"a8m.column\"]]\n    ref_columns = [table[\"a8m.table\"].column[\"a8m.column\"]]\n  }\n}\nschema \"a8m.schema\" {\n}\nschema \"nati.schema\" {\n}\n`, string(got))\n}\n"
  },
  {
    "path": "sql/mysql/tidb.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage mysql\n\nimport (\n\t\"context\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\ntype (\n\t// tplanApply decorates MySQL planApply.\n\ttplanApply struct{ planApply }\n\t// tdiff decorates MySQL diff.\n\ttdiff struct{ diff }\n\t// tinspect decorates MySQL inspect.\n\ttinspect struct{ inspect }\n)\n\n// priority computes the priority of each change.\n//\n// TiDB does not support multischema ALTERs (i.e. multiple changes in a single ALTER statement).\n// Therefore, we have to break down each alter. This function helps order the ALTERs so they work.\n// e.g. priority gives precedence to DropForeignKey over DropColumn, because a column cannot be\n// dropped if its foreign key was not dropped before.\nfunc priority(change schema.Change) int {\n\tswitch c := change.(type) {\n\tcase *schema.ModifyTable:\n\t\t// each modifyTable should have a single change since we apply `flat` before we sort.\n\t\treturn priority(c.Changes[0])\n\tcase *schema.ModifySchema:\n\t\t// each modifyTable should have a single change since we apply `flat` before we sort.\n\t\treturn priority(c.Changes[0])\n\tcase *schema.AddColumn:\n\t\treturn 1\n\tcase *schema.DropIndex, *schema.DropForeignKey, *schema.DropAttr, *schema.DropCheck:\n\t\treturn 2\n\tcase *schema.ModifyIndex, *schema.ModifyForeignKey:\n\t\treturn 3\n\tdefault:\n\t\treturn 4\n\t}\n}\n\n// flat takes a list of changes and breaks them down to single atomic changes (e.g: no ModifyTable\n// with multiple AddColumn inside it). Note that, the only \"changes\" that include sub-changes are\n// `ModifyTable` and `ModifySchema`.\nfunc flat(changes []schema.Change) []schema.Change {\n\tvar flat []schema.Change\n\tfor _, change := range changes {\n\t\tswitch m := change.(type) {\n\t\tcase *schema.ModifyTable:\n\t\t\tfor _, c := range m.Changes {\n\t\t\t\tflat = append(flat, &schema.ModifyTable{\n\t\t\t\t\tT:       m.T,\n\t\t\t\t\tChanges: []schema.Change{c},\n\t\t\t\t})\n\t\t\t}\n\t\tcase *schema.ModifySchema:\n\t\t\tfor _, c := range m.Changes {\n\t\t\t\tflat = append(flat, &schema.ModifySchema{\n\t\t\t\t\tS:       m.S,\n\t\t\t\t\tChanges: []schema.Change{c},\n\t\t\t\t})\n\t\t\t}\n\t\tdefault:\n\t\t\tflat = append(flat, change)\n\t\t}\n\t}\n\treturn flat\n}\n\n// PlanChanges returns a migration plan for the given schema changes.\nfunc (p *tplanApply) PlanChanges(ctx context.Context, name string, changes []schema.Change, opts ...migrate.PlanOption) (*migrate.Plan, error) {\n\tplanned, err := sqlx.DetachCycles(changes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tplanned = flat(planned)\n\tsort.SliceStable(planned, func(i, j int) bool {\n\t\treturn priority(planned[i]) < priority(planned[j])\n\t})\n\ts := &state{\n\t\tconn: p.conn,\n\t\tPlan: migrate.Plan{\n\t\t\tName: name,\n\t\t\t// A plan is reversible, if all\n\t\t\t// its changes are reversible.\n\t\t\tReversible:    true,\n\t\t\tTransactional: false,\n\t\t},\n\t}\n\tfor _, c := range planned {\n\t\t// Use the planner of MySQL with each \"atomic\" change.\n\t\tplan, err := p.planApply.PlanChanges(ctx, name, []schema.Change{c}, opts...)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif !plan.Reversible {\n\t\t\ts.Plan.Reversible = false\n\t\t}\n\t\ts.Plan.Changes = append(s.Plan.Changes, plan.Changes...)\n\t}\n\treturn &s.Plan, nil\n}\n\nfunc (p *tplanApply) ApplyChanges(ctx context.Context, changes []schema.Change, opts ...migrate.PlanOption) error {\n\treturn sqlx.ApplyChanges(ctx, changes, p, opts...)\n}\n\nfunc (i *tinspect) InspectSchema(ctx context.Context, name string, opts *schema.InspectOptions) (*schema.Schema, error) {\n\ts, err := i.inspect.InspectSchema(ctx, name, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn i.patchSchema(ctx, s)\n}\n\nfunc (i *tinspect) InspectRealm(ctx context.Context, opts *schema.InspectRealmOption) (*schema.Realm, error) {\n\tr, err := i.inspect.InspectRealm(ctx, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, s := range r.Schemas {\n\t\tif _, err := i.patchSchema(ctx, s); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn r, nil\n}\n\nfunc (i *tinspect) patchSchema(ctx context.Context, s *schema.Schema) (*schema.Schema, error) {\n\tfor _, t := range s.Tables {\n\t\tvar createStmt CreateStmt\n\t\tif ok := sqlx.Has(t.Attrs, &createStmt); !ok {\n\t\t\tif _, err := i.createStmt(ctx, t); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tif err := i.setCollate(t); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := i.setAutoIncrement(t); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tfor _, c := range t.Columns {\n\t\t\ti.patchColumn(ctx, c)\n\t\t}\n\t}\n\treturn s, nil\n}\n\nfunc (i *tinspect) patchColumn(_ context.Context, c *schema.Column) {\n\t_, ok := c.Type.Type.(*BitType)\n\tif !ok {\n\t\treturn\n\t}\n\t// TiDB has a bug where it does not format bit default value correctly.\n\tif lit, ok := c.Default.(*schema.Literal); ok && !strings.HasPrefix(lit.V, \"b'\") {\n\t\tlit.V = bytesToBitLiteral([]byte(lit.V))\n\t}\n}\n\n// bytesToBitLiteral converts a bytes to MySQL bit literal.\n// e.g. []byte{4} -> b'100', []byte{2,1} -> b'1000000001'.\n// See: https://github.com/pingcap/tidb/issues/32655.\nfunc bytesToBitLiteral(b []byte) string {\n\tbytes := make([]byte, 8)\n\tfor i := 0; i < len(b); i++ {\n\t\tbytes[8-len(b)+i] = b[i]\n\t}\n\tval := binary.BigEndian.Uint64(bytes)\n\treturn fmt.Sprintf(\"b'%b'\", val)\n}\n\n// e.g CHARSET=utf8mb4 COLLATE=utf8mb4_bin\nvar reColl = regexp.MustCompile(`(?i)CHARSET\\s*=\\s*(\\w+)\\s*COLLATE\\s*=\\s*(\\w+)`)\n\n// setCollate extracts the updated Collation from CREATE TABLE statement.\nfunc (i *tinspect) setCollate(t *schema.Table) error {\n\tvar c CreateStmt\n\tif !sqlx.Has(t.Attrs, &c) {\n\t\treturn fmt.Errorf(\"missing CREATE TABLE statement in attributes for %q\", t.Name)\n\t}\n\tmatches := reColl.FindStringSubmatch(c.S)\n\tif len(matches) != 3 {\n\t\treturn fmt.Errorf(\"missing COLLATE and/or CHARSET information on CREATE TABLE statement for %q\", t.Name)\n\t}\n\tt.SetCharset(matches[1])\n\tt.SetCollation(matches[2])\n\treturn nil\n}\n\n// setCollate extracts the updated Collation from CREATE TABLE statement.\nfunc (i *tinspect) setAutoIncrement(t *schema.Table) error {\n\t// patch only it is set (set falsely to '1' due to this bug:https://github.com/pingcap/tidb/issues/24702).\n\tai := &AutoIncrement{}\n\tif !sqlx.Has(t.Attrs, ai) {\n\t\treturn nil\n\t}\n\tvar c CreateStmt\n\tif !sqlx.Has(t.Attrs, &c) {\n\t\treturn fmt.Errorf(\"missing CREATE TABLE statement in attributes for %q\", t.Name)\n\t}\n\tmatches := reAutoinc.FindStringSubmatch(c.S)\n\tif len(matches) != 2 {\n\t\treturn nil\n\t}\n\tv, err := strconv.ParseInt(matches[1], 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\tai.V = v\n\tschema.ReplaceOrAppend(&t.Attrs, ai)\n\treturn nil\n}\n"
  },
  {
    "path": "sql/postgres/convert.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage postgres\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// FormatType converts schema type to its column form in the database.\n// An error is returned if the type cannot be recognized.\nfunc FormatType(t schema.Type) (string, error) {\n\tvar f string\n\tswitch t := t.(type) {\n\tcase *ArrayType:\n\t\tf = strings.ToLower(t.T)\n\tcase *BitType:\n\t\tf = strings.ToLower(t.T)\n\t\t// BIT without a length is equivalent to BIT(1),\n\t\t// BIT VARYING has unlimited length.\n\t\tif f == TypeBit && t.Len > 1 || f == TypeBitVar && t.Len > 0 {\n\t\t\tf = fmt.Sprintf(\"%s(%d)\", f, t.Len)\n\t\t}\n\tcase *schema.BoolType:\n\t\t// BOOLEAN can be abbreviated as BOOL.\n\t\tif f = strings.ToLower(t.T); f == TypeBool {\n\t\t\tf = TypeBoolean\n\t\t}\n\tcase *schema.BinaryType:\n\t\tf = strings.ToLower(t.T)\n\tcase *CurrencyType:\n\t\tf = strings.ToLower(t.T)\n\tcase *CompositeType:\n\t\tif t.T == \"\" {\n\t\t\treturn \"\", errors.New(\"postgres: missing composite type name\")\n\t\t}\n\t\tf = t.T\n\tcase *RowType:\n\t\tif t.T == nil || t.T.Name == \"\" {\n\t\t\treturn \"\", errors.New(\"postgres: missing table for composite (row) type\")\n\t\t}\n\t\tf = t.T.Name\n\tcase *DomainType:\n\t\tif t.T == \"\" {\n\t\t\treturn \"\", errors.New(\"postgres: missing domain type name\")\n\t\t}\n\t\tf = t.T\n\tcase *schema.EnumType:\n\t\tif t.T == \"\" {\n\t\t\treturn \"\", errors.New(\"postgres: missing enum type name\")\n\t\t}\n\t\tf = t.T\n\tcase *schema.IntegerType:\n\t\tswitch f = strings.ToLower(t.T); f {\n\t\tcase TypeXID, TypeXID8:\n\t\tcase TypeSmallInt, TypeInteger, TypeBigInt:\n\t\tcase TypeInt2:\n\t\t\tf = TypeSmallInt\n\t\tcase TypeInt, TypeInt4:\n\t\t\tf = TypeInteger\n\t\tcase TypeInt8:\n\t\t\tf = TypeBigInt\n\t\t}\n\tcase *IntervalType:\n\t\tf = strings.ToLower(t.T)\n\t\tif t.F != \"\" {\n\t\t\tf += \" \" + strings.ToLower(t.F)\n\t\t}\n\t\tif t.Precision != nil && *t.Precision != defaultTimePrecision {\n\t\t\tf += fmt.Sprintf(\"(%d)\", *t.Precision)\n\t\t}\n\tcase *schema.StringType:\n\t\tswitch f = strings.ToLower(t.T); f {\n\t\tcase TypeText, TypeBPChar, typeName:\n\t\t// CHAR(n) is alias for CHARACTER(n). If not length was\n\t\t// specified, the definition is equivalent to CHARACTER(1).\n\t\tcase TypeChar, TypeCharacter:\n\t\t\tn := t.Size\n\t\t\tif n == 0 {\n\t\t\t\tn = 1\n\t\t\t}\n\t\t\tf = fmt.Sprintf(\"%s(%d)\", TypeCharacter, n)\n\t\t// VARCHAR(n) is alias for CHARACTER VARYING(n). If not length\n\t\t// was specified, the type accepts strings of any size.\n\t\tcase TypeVarChar, TypeCharVar:\n\t\t\tf = TypeCharVar\n\t\t\tif t.Size != 0 {\n\t\t\t\tf = fmt.Sprintf(\"%s(%d)\", TypeCharVar, t.Size)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn \"\", fmt.Errorf(\"postgres: unexpected string type: %q\", t.T)\n\t\t}\n\tcase *schema.TimeType:\n\t\tf = timeAlias(t.T)\n\t\tif p := t.Precision; p != nil && *p != defaultTimePrecision && strings.HasPrefix(f, \"time\") {\n\t\t\tf += fmt.Sprintf(\"(%d)\", *p)\n\t\t}\n\tcase *schema.FloatType:\n\t\tswitch f = strings.ToLower(t.T); f {\n\t\tcase TypeFloat4:\n\t\t\tf = TypeReal\n\t\tcase TypeFloat8:\n\t\t\tf = TypeDouble\n\t\tcase TypeFloat:\n\t\t\tswitch {\n\t\t\tcase t.Precision > 0 && t.Precision <= 24:\n\t\t\t\tf = TypeReal\n\t\t\tcase t.Precision == 0 || (t.Precision > 24 && t.Precision <= 53):\n\t\t\t\tf = TypeDouble\n\t\t\tdefault:\n\t\t\t\treturn \"\", fmt.Errorf(\"postgres: precision for type float must be between 1 and 53: %d\", t.Precision)\n\t\t\t}\n\t\t}\n\tcase *schema.DecimalType:\n\t\tswitch f = strings.ToLower(t.T); f {\n\t\tcase TypeNumeric:\n\t\t// The DECIMAL type is an alias for NUMERIC.\n\t\tcase TypeDecimal:\n\t\t\tf = TypeNumeric\n\t\tdefault:\n\t\t\treturn \"\", fmt.Errorf(\"postgres: unexpected decimal type: %q\", t.T)\n\t\t}\n\t\tswitch p, s := t.Precision, t.Scale; {\n\t\tcase p == 0 && s == 0:\n\t\tcase s < 0:\n\t\t\treturn \"\", fmt.Errorf(\"postgres: decimal type must have scale >= 0: %d\", s)\n\t\tcase p == 0 && s > 0:\n\t\t\treturn \"\", fmt.Errorf(\"postgres: decimal type must have precision between 1 and 1000: %d\", p)\n\t\tcase s == 0:\n\t\t\tf = fmt.Sprintf(\"%s(%d)\", f, p)\n\t\tdefault:\n\t\t\tf = fmt.Sprintf(\"%s(%d,%d)\", f, p, s)\n\t\t}\n\tcase *SerialType:\n\t\tswitch f = strings.ToLower(t.T); f {\n\t\tcase TypeSmallSerial, TypeSerial, TypeBigSerial:\n\t\tcase TypeSerial2:\n\t\t\tf = TypeSmallSerial\n\t\tcase TypeSerial4:\n\t\t\tf = TypeSerial\n\t\tcase TypeSerial8:\n\t\t\tf = TypeBigSerial\n\t\tdefault:\n\t\t\treturn \"\", fmt.Errorf(\"postgres: unexpected serial type: %q\", t.T)\n\t\t}\n\tcase *schema.JSONType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.UUIDType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.SpatialType:\n\t\tf = strings.ToLower(t.T)\n\tcase *NetworkType:\n\t\tf = strings.ToLower(t.T)\n\tcase *RangeType:\n\t\tswitch f = strings.ToLower(t.T); f {\n\t\tcase TypeInt4Range, TypeInt4MultiRange, TypeInt8Range, TypeInt8MultiRange, TypeNumRange, TypeNumMultiRange,\n\t\t\tTypeTSRange, TypeTSMultiRange, TypeTSTZRange, TypeTSTZMultiRange, TypeDateRange, TypeDateMultiRange:\n\t\tdefault:\n\t\t\treturn \"\", fmt.Errorf(\"postgres: unsupported range type: %q\", t.T)\n\t\t}\n\tcase *OIDType:\n\t\tswitch f = strings.ToLower(t.T); f {\n\t\tcase typeOID, typeRegClass, typeRegCollation, typeRegConfig, typeRegDictionary, typeRegNamespace,\n\t\t\ttypeRegOper, typeRegOperator, typeRegProc, typeRegProcedure, typeRegRole, typeRegType:\n\t\tdefault:\n\t\t\treturn \"\", fmt.Errorf(\"postgres: unsupported object identifier type: %q\", t.T)\n\t\t}\n\tcase *TextSearchType:\n\t\tif f = strings.ToLower(t.T); f != TypeTSVector && f != TypeTSQuery {\n\t\t\treturn \"\", fmt.Errorf(\"postgres: unsupported text search type: %q\", t.T)\n\t\t}\n\tcase *UserDefinedType:\n\t\tf = t.T\n\tcase *XMLType:\n\t\tf = strings.ToLower(t.T)\n\tcase *PseudoType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.UnsupportedType:\n\t\treturn \"\", fmt.Errorf(\"postgres: unsupported type: %q\", t.T)\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"postgres: invalid schema type: %T\", t)\n\t}\n\treturn f, nil\n}\n\n// ParseType returns the schema.Type value represented by the given raw type.\n// The raw value is expected to follow the format in PostgreSQL information schema\n// or as an input for the CREATE TABLE statement.\nfunc ParseType(typ string) (schema.Type, error) {\n\tvar (\n\t\terr error\n\t\td   *columnDesc\n\t)\n\t// Normalize PostgreSQL array data types from \"CREATE TABLE\" format to\n\t// \"INFORMATION_SCHEMA\" format (i.e. as it is inspected from the database).\n\tif t, ok := arrayType(typ); ok {\n\t\td = &columnDesc{typ: TypeArray, fmtype: t + \"[]\"}\n\t} else if d, err = parseColumn(typ); err != nil {\n\t\treturn nil, err\n\t}\n\tt, err := columnType(d)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// If the type is unknown (to us), we fall back to user-defined but expect\n\t// to improve this in future versions by ensuring this against the database.\n\tif ut, ok := t.(*schema.UnsupportedType); ok {\n\t\tt = &UserDefinedType{T: ut.T}\n\t}\n\treturn t, nil\n}\n\nfunc columnType(c *columnDesc) (schema.Type, error) {\n\tvar typ schema.Type\n\tswitch t := c.typ; strings.ToLower(t) {\n\tcase TypeBigInt, TypeInt8, TypeInt, TypeInteger, TypeInt4, TypeSmallInt, TypeInt2, TypeInt64, TypeXID, TypeXID8:\n\t\ttyp = &schema.IntegerType{T: t}\n\tcase TypeBit, TypeBitVar:\n\t\ttyp = &BitType{T: t, Len: c.size}\n\tcase TypeBool, TypeBoolean:\n\t\ttyp = &schema.BoolType{T: t}\n\tcase TypeBytea:\n\t\ttyp = &schema.BinaryType{T: t}\n\tcase TypeCharacter, TypeChar, TypeCharVar, TypeVarChar, TypeText, TypeBPChar, typeName:\n\t\tif t == TypeCharacter && c.size == 0 && c.fmtype == TypeBPChar {\n\t\t\tt = TypeBPChar\n\t\t}\n\t\t// A `character` column without length specifier is equivalent to `character(1)`,\n\t\t// but `varchar` without length accepts strings of any size (same as `text`).\n\t\ttyp = &schema.StringType{T: t, Size: int(c.size)}\n\tcase TypeCIDR, TypeInet, TypeMACAddr, TypeMACAddr8:\n\t\ttyp = &NetworkType{T: t}\n\tcase TypeCircle, TypeLine, TypeLseg, TypeBox, TypePath, TypePolygon, TypePoint, TypeGeometry:\n\t\ttyp = &schema.SpatialType{T: t}\n\tcase TypeDate:\n\t\ttyp = &schema.TimeType{T: t}\n\tcase TypeTime, TypeTimeWOTZ, TypeTimeTZ, TypeTimeWTZ, TypeTimestamp,\n\t\tTypeTimestampTZ, TypeTimestampWTZ, TypeTimestampWOTZ:\n\t\tp := defaultTimePrecision\n\t\tif c.timePrecision != nil {\n\t\t\tp = int(*c.timePrecision)\n\t\t}\n\t\ttyp = &schema.TimeType{T: t, Precision: &p}\n\tcase TypeInterval:\n\t\tp := defaultTimePrecision\n\t\tif c.timePrecision != nil {\n\t\t\tp = int(*c.timePrecision)\n\t\t}\n\t\ttyp = &IntervalType{T: t, Precision: &p}\n\t\tif c.interval != \"\" {\n\t\t\tf, ok := intervalField(c.interval)\n\t\t\tif !ok {\n\t\t\t\treturn &schema.UnsupportedType{T: c.interval}, nil\n\t\t\t}\n\t\t\ttyp.(*IntervalType).F = f\n\t\t}\n\tcase TypeReal, TypeDouble, TypeFloat, TypeFloat4, TypeFloat8:\n\t\ttyp = &schema.FloatType{T: t, Precision: int(c.precision)}\n\tcase TypeJSON, TypeJSONB:\n\t\ttyp = &schema.JSONType{T: t}\n\tcase TypeMoney:\n\t\ttyp = &CurrencyType{T: t}\n\tcase TypeDecimal, TypeNumeric:\n\t\ttyp = &schema.DecimalType{T: t, Precision: int(c.precision), Scale: int(c.scale)}\n\tcase TypeSmallSerial, TypeSerial, TypeBigSerial, TypeSerial2, TypeSerial4, TypeSerial8:\n\t\ttyp = &SerialType{T: t, Precision: int(c.precision)}\n\tcase TypeUUID:\n\t\ttyp = &schema.UUIDType{T: t}\n\tcase TypeXML:\n\t\ttyp = &XMLType{T: t}\n\tcase TypeArray:\n\t\t// Ignore multi-dimensions or size constraints\n\t\t// as they are ignored by the database.\n\t\ttyp = &ArrayType{T: c.fmtype}\n\t\tif t, ok := arrayType(c.fmtype); ok {\n\t\t\ttt, err := ParseType(t)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ttyp.(*ArrayType).Type = tt\n\t\t}\n\tcase TypeTSVector, TypeTSQuery:\n\t\ttyp = &TextSearchType{T: t}\n\tcase TypeInt4Range, TypeInt4MultiRange, TypeInt8Range, TypeInt8MultiRange, TypeNumRange, TypeNumMultiRange,\n\t\tTypeTSRange, TypeTSMultiRange, TypeTSTZRange, TypeTSTZMultiRange, TypeDateRange, TypeDateMultiRange:\n\t\ttyp = &RangeType{T: t}\n\tcase typeOID, typeRegClass, typeRegCollation, typeRegConfig, typeRegDictionary, typeRegNamespace,\n\t\ttypeRegOper, typeRegOperator, typeRegProc, typeRegProcedure, typeRegRole, typeRegType:\n\t\ttyp = &OIDType{T: t}\n\tcase typeAny, typeAnyElement, typeAnyArray, typeAnyNonArray, typeAnyEnum, typeInternal,\n\t\ttypeRecord, typeTrigger, typeEventTrigger, typeVoid, typeUnknown:\n\t\ttyp = &PseudoType{T: t}\n\t// TypeUserDefined or any other base type.\n\tdefault:\n\t\tft := c.fmtype\n\t\tif ft == \"\" {\n\t\t\tft = t\n\t\t}\n\t\ttyp = &UserDefinedType{T: ft, C: c.typtype}\n\t}\n\tswitch c.typtype {\n\tcase \"d\", \"e\":\n\t\t// User-defined types supported by Atlas.\n\t\ttyp = &UserDefinedType{T: c.fmtype, C: c.typtype}\n\t}\n\treturn typ, nil\n}\n\n// reArray parses array declaration. See: https://postgresql.org/docs/current/arrays.html.\nvar reArray = regexp.MustCompile(`(?i)(.+?)(( +ARRAY( *\\[[ \\d]*] *)*)+|( *\\[[ \\d]*] *)+)$`)\n\n// arrayType reports if the given string is an array type (e.g. int[], text[2]),\n// and returns its \"udt_name\" as it was inspected from the database.\nfunc arrayType(t string) (string, bool) {\n\tmatches := reArray.FindStringSubmatch(t)\n\tif len(matches) < 2 {\n\t\treturn \"\", false\n\t}\n\treturn strings.TrimSpace(matches[1]), true\n}\n\n// reInterval parses declaration of interval fields. See: https://www.postgresql.org/docs/current/datatype-datetime.html.\nvar reInterval = regexp.MustCompile(`(?i)(?:INTERVAL\\s*)?(YEAR|MONTH|DAY|HOUR|MINUTE|SECOND|YEAR TO MONTH|DAY TO HOUR|DAY TO MINUTE|DAY TO SECOND|HOUR TO MINUTE|HOUR TO SECOND|MINUTE TO SECOND)?\\s*(?:\\(([0-6])\\))?$`)\n\n// intervalField reports if the given string is an interval\n// field type and returns its value (e.g. SECOND, MINUTE TO SECOND).\nfunc intervalField(t string) (string, bool) {\n\tmatches := reInterval.FindStringSubmatch(t)\n\tif len(matches) != 3 || matches[1] == \"\" {\n\t\treturn \"\", false\n\t}\n\treturn matches[1], true\n}\n\n// columnDesc represents a column descriptor.\ntype columnDesc struct {\n\ttyp           string // data_type\n\tfmtype        string // pg_catalog.format_type\n\tsize          int64  // character_maximum_length\n\ttyptype       string // pg_type.typtype\n\ttypelem       int64  // pg_type.typelem\n\ttypid         int64  // pg_type.oid\n\tprecision     int64\n\ttimePrecision *int64\n\tscale         int64\n\tparts         []string\n\tinterval      string\n}\n\nvar reDigits = regexp.MustCompile(`\\d`)\n\nfunc parseColumn(s string) (*columnDesc, error) {\n\tif s == \"\" {\n\t\treturn nil, errors.New(\"postgres: unexpected empty column type\")\n\t}\n\tparts := strings.FieldsFunc(s, func(r rune) bool {\n\t\treturn r == '(' || r == ')' || r == ' ' || r == ','\n\t})\n\tvar (\n\t\terr error\n\t\tc   = &columnDesc{\n\t\t\ttyp:   parts[0],\n\t\t\tparts: parts,\n\t\t}\n\t)\n\tswitch c.parts[0] {\n\tcase TypeVarChar, TypeCharVar, TypeChar, TypeCharacter:\n\t\tif err := parseCharParts(c.parts, c); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase TypeDecimal, TypeNumeric, TypeFloat:\n\t\tif len(parts) > 1 {\n\t\t\tc.precision, err = strconv.ParseInt(parts[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"postgres: parse precision %q: %w\", parts[1], err)\n\t\t\t}\n\t\t}\n\t\tif len(parts) > 2 {\n\t\t\tc.scale, err = strconv.ParseInt(parts[2], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"postgres: parse scale %q: %w\", parts[1], err)\n\t\t\t}\n\t\t}\n\tcase TypeBit:\n\t\tif err := parseBitParts(parts, c); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase TypeDouble, TypeFloat8:\n\t\tc.precision = 53\n\tcase TypeReal, TypeFloat4:\n\t\tc.precision = 24\n\tcase TypeTime, TypeTimeTZ, TypeTimestamp, TypeTimestampTZ:\n\t\tt, p := s, int64(defaultTimePrecision)\n\t\t// If the second part is only one digit it is the precision argument.\n\t\t// For cases like \"timestamp(4) with time zone\" make sure to not drop\n\t\t// the rest of the type definition.\n\t\tif len(parts) > 1 && reDigits.MatchString(parts[1]) {\n\t\t\ti, err := strconv.ParseInt(parts[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"postgres: parse time precision %q: %w\", parts[1], err)\n\t\t\t}\n\t\t\tp = i\n\t\t\tt = strings.Join(append(c.parts[:1], c.parts[2:]...), \" \")\n\t\t}\n\t\tc.typ = timeAlias(t)\n\t\tc.timePrecision = &p\n\tcase TypeInterval:\n\t\tmatches := reInterval.FindStringSubmatch(s)\n\t\tc.interval = matches[1]\n\t\tif matches[2] != \"\" {\n\t\t\ti, err := strconv.ParseInt(matches[2], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"postgres: parse interval precision %q: %w\", parts[1], err)\n\t\t\t}\n\t\t\tc.timePrecision = &i\n\t\t}\n\tdefault:\n\t\tc.typ = s\n\t}\n\treturn c, nil\n}\n\nfunc parseCharParts(parts []string, c *columnDesc) error {\n\tj := strings.Join(parts, \" \")\n\tswitch {\n\tcase strings.HasPrefix(j, TypeVarChar):\n\t\tc.typ = TypeVarChar\n\t\tparts = parts[1:]\n\tcase strings.HasPrefix(j, TypeCharVar):\n\t\tc.typ = TypeCharVar\n\t\tparts = parts[2:]\n\tdefault:\n\t\tparts = parts[1:]\n\t}\n\tif len(parts) == 0 {\n\t\treturn nil\n\t}\n\tsize, err := strconv.ParseInt(parts[0], 10, 64)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"postgres: parse size %q: %w\", parts[0], err)\n\t}\n\tc.size = size\n\treturn nil\n}\n\nfunc parseBitParts(parts []string, c *columnDesc) error {\n\tif len(parts) == 1 {\n\t\tc.size = 1\n\t\treturn nil\n\t}\n\tparts = parts[1:]\n\tif parts[0] == \"varying\" {\n\t\tc.typ = TypeBitVar\n\t\tparts = parts[1:]\n\t}\n\tif len(parts) == 0 {\n\t\treturn nil\n\t}\n\tsize, err := strconv.ParseInt(parts[0], 10, 64)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"postgres: parse size %q: %w\", parts[1], err)\n\t}\n\tc.size = size\n\treturn nil\n}\n\n// timeAlias returns the abbreviation for the given time type.\nfunc timeAlias(t string) string {\n\tswitch t = strings.ToLower(t); t {\n\t// TIMESTAMPTZ be equivalent to TIMESTAMP WITH TIME ZONE.\n\tcase TypeTimestampWTZ:\n\t\tt = TypeTimestampTZ\n\t// TIMESTAMP be equivalent to TIMESTAMP WITHOUT TIME ZONE.\n\tcase TypeTimestampWOTZ:\n\t\tt = TypeTimestamp\n\t// TIME be equivalent to TIME WITHOUT TIME ZONE.\n\tcase TypeTimeWOTZ:\n\t\tt = TypeTime\n\t// TIMETZ be equivalent to TIME WITH TIME ZONE.\n\tcase TypeTimeWTZ:\n\t\tt = TypeTimeTZ\n\t}\n\treturn t\n}\n"
  },
  {
    "path": "sql/postgres/crdb_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\ntype (\n\tcrdbDiff    struct{ diff }\n\tcrdbInspect struct{ inspect }\n\tnoLocker    interface {\n\t\tmigrate.Driver\n\t\tschema.Normalizer\n\t}\n\tnoLockDriver struct {\n\t\tnoLocker\n\t}\n)\n\nvar _ sqlx.DiffDriver = (*crdbDiff)(nil)\n\n// pathSchema fixes: https://github.com/cockroachdb/cockroach/issues/82040.\nfunc (i *crdbInspect) patchSchema(s *schema.Schema) {\n\tfor _, t := range s.Tables {\n\t\tfor _, c := range t.Columns {\n\t\t\tid, ok := identity(c.Attrs)\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tc.Default = nil\n\t\t\tif g := strings.ToUpper(id.Generation); strings.Contains(g, \"ALWAYS\") {\n\t\t\t\tid.Generation = \"ALWAYS\"\n\t\t\t} else if strings.Contains(g, \"BY DEFAULT\") {\n\t\t\t\tid.Generation = \"BY DEFAULT\"\n\t\t\t}\n\t\t\tschema.ReplaceOrAppend(&c.Attrs, id)\n\t\t}\n\t}\n}\n\nfunc (i *crdbInspect) InspectSchema(ctx context.Context, name string, opts *schema.InspectOptions) (*schema.Schema, error) {\n\ts, err := i.inspect.InspectSchema(ctx, name, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ti.patchSchema(s)\n\treturn s, err\n}\n\nfunc (i *crdbInspect) InspectRealm(ctx context.Context, opts *schema.InspectRealmOption) (*schema.Realm, error) {\n\tr, err := i.inspect.InspectRealm(ctx, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, s := range r.Schemas {\n\t\ti.patchSchema(s)\n\t}\n\treturn r, nil\n}\n\n// Normalize implements the sqlx.Normalizer.\nfunc (cd *crdbDiff) Normalize(from, to *schema.Table, _ *schema.DiffOptions) error {\n\tcd.normalize(from)\n\tcd.normalize(to)\n\treturn nil\n}\n\nfunc (cd *crdbDiff) ColumnChange(fromT *schema.Table, from, to *schema.Column, opts *schema.DiffOptions) (schema.Change, error) {\n\t// All serial types in Cockroach are implemented as bigint.\n\t// See: https://www.cockroachlabs.com/docs/stable/serial.html#generated-values-for-mode-sql_sequence-and-sql_sequence_cached.\n\tfor _, c := range []*schema.Column{from, to} {\n\t\tif _, ok := c.Type.Type.(*SerialType); ok {\n\t\t\tc.Type.Type = &schema.IntegerType{\n\t\t\t\tT: TypeBigInt,\n\t\t\t}\n\t\t\tto.Default = nil\n\t\t\tfrom.Default = nil\n\t\t}\n\t}\n\treturn cd.diff.ColumnChange(fromT, from, to, opts)\n}\n\nfunc (cd *crdbDiff) normalize(table *schema.Table) {\n\tif table.PrimaryKey == nil {\n\t\tprim, ok := table.Column(\"rowid\")\n\t\tif !ok {\n\t\t\tprim = schema.NewColumn(\"rowid\").\n\t\t\t\tAddAttrs(Identity{}).\n\t\t\t\tSetType(&schema.IntegerType{T: TypeBigInt}).\n\t\t\t\tSetDefault(&schema.RawExpr{X: \"unique_rowid()\"})\n\t\t\ttable.AddColumns(prim)\n\t\t}\n\t\ttable.PrimaryKey = &schema.Index{\n\t\t\tName:   \"primary\",\n\t\t\tUnique: true,\n\t\t\tTable:  table,\n\t\t\tParts: []*schema.IndexPart{{\n\t\t\t\tSeqNo: 1,\n\t\t\t\tC:     prim,\n\t\t\t}},\n\t\t}\n\t}\n\tfor _, c := range table.Columns {\n\t\tif _, ok := identity(c.Attrs); ok {\n\t\t\tif c.Default != nil {\n\t\t\t\tc.Default = nil\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tswitch t := c.Type.Type.(type) {\n\t\t// Integer types are aliased.\n\t\t// see: cockroachlabs.com/docs/v21.2/int.html#names-and-aliases.\n\t\tcase *schema.IntegerType:\n\t\t\tswitch t.T {\n\t\t\tcase TypeBigInt, TypeInteger, TypeInt8, TypeInt64, TypeInt:\n\t\t\t\tt.T = TypeBigInt\n\t\t\tcase TypeInt2, TypeSmallInt:\n\t\t\t\tt.T = TypeSmallInt\n\t\t\t}\n\t\tcase *schema.JSONType:\n\t\t\tswitch t.T {\n\t\t\t// Type json is aliased to jsonb.\n\t\t\tcase TypeJSON:\n\t\t\t\tt.T = TypeJSONB\n\t\t\t}\n\t\tcase *SerialType:\n\t\t\tc.Default = &schema.RawExpr{\n\t\t\t\tX: \"unique_rowid()\",\n\t\t\t}\n\t\tcase *schema.TimeType:\n\t\t\t// \"timestamp\" and \"timestamptz\" are accepted as\n\t\t\t// abbreviations for timestamp with(out) time zone.\n\t\t\tswitch t.T {\n\t\t\tcase \"timestamp with time zone\":\n\t\t\t\tt.T = \"timestamptz\"\n\t\t\tcase \"timestamp without time zone\":\n\t\t\t\tt.T = \"timestamp\"\n\t\t\t}\n\t\tcase *schema.FloatType:\n\t\t\t// The same numeric precision is used in all platform.\n\t\t\t// See: https://www.postgresql.org/docs/current/datatype-numeric.html\n\t\t\tswitch {\n\t\t\tcase t.T == \"float\" && t.Precision < 25:\n\t\t\t\t// float(1) to float(24) are selected as \"real\" type.\n\t\t\t\tt.T = \"real\"\n\t\t\t\tfallthrough\n\t\t\tcase t.T == \"real\":\n\t\t\t\tt.Precision = 24\n\t\t\tcase t.T == \"float\" && t.Precision >= 25:\n\t\t\t\t// float(25) to float(53) are selected as \"double precision\" type.\n\t\t\t\tt.T = \"double precision\"\n\t\t\t\tfallthrough\n\t\t\tcase t.T == \"double precision\":\n\t\t\t\tt.Precision = 53\n\t\t\t}\n\t\tcase *schema.StringType:\n\t\t\tswitch t.T {\n\t\t\tcase \"character\", \"char\":\n\t\t\t\t// Character without length specifier\n\t\t\t\t// is equivalent to character(1).\n\t\t\t\tt.Size = 1\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (i *inspect) crdbIndexes(ctx context.Context, s *schema.Schema) error {\n\trows, err := i.querySchema(ctx, crdbIndexesQuery, s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"postgres: querying schema %q indexes: %w\", s.Name, err)\n\t}\n\tdefer rows.Close()\n\tif err := i.crdbAddIndexes(s, rows); err != nil {\n\t\treturn err\n\t}\n\treturn rows.Err()\n}\n\nvar reIndexType = regexp.MustCompile(\"(?i)USING (BTREE|GIN|GIST)\")\n\nfunc (i *inspect) crdbAddIndexes(s *schema.Schema, rows *sql.Rows) error {\n\t// Unlike Postgres, Cockroach may have duplicate index names.\n\tnames := make(map[string]*schema.Index)\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tuniq, primary                        bool\n\t\t\ttable, name, createStmt              string\n\t\t\tcolumn, contype, pred, expr, comment sql.NullString\n\t\t)\n\t\tif err := rows.Scan(&table, &name, &column, &primary, &uniq, &contype, &createStmt, &pred, &expr, &comment); err != nil {\n\t\t\treturn fmt.Errorf(\"cockroach: scanning indexes for schema %q: %w\", s.Name, err)\n\t\t}\n\t\tt, ok := s.Table(table)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"table %q was not found in schema\", table)\n\t\t}\n\t\tuniqueName := fmt.Sprintf(\"%s.%s\", table, name)\n\t\tidx, ok := names[uniqueName]\n\t\tif !ok {\n\t\t\tidx = &schema.Index{\n\t\t\t\tName:   name,\n\t\t\t\tUnique: uniq,\n\t\t\t\tTable:  t,\n\t\t\t}\n\t\t\t// Extract index type information from index create statement.\n\t\t\t// See: https://www.cockroachlabs.com/docs/stable/create-index.html.\n\t\t\tif parts := reIndexType.FindStringSubmatch(createStmt); len(parts) > 0 {\n\t\t\t\tidx.Attrs = append(idx.Attrs, &IndexType{T: parts[1]})\n\t\t\t}\n\t\t\tif sqlx.ValidString(comment) {\n\t\t\t\tidx.Attrs = append(idx.Attrs, &schema.Comment{Text: comment.String})\n\t\t\t}\n\t\t\tif sqlx.ValidString(contype) {\n\t\t\t\tidx.Attrs = append(idx.Attrs, &Constraint{T: contype.String})\n\t\t\t}\n\t\t\tif sqlx.ValidString(pred) {\n\t\t\t\tidx.Attrs = append(idx.Attrs, &IndexPredicate{P: pred.String})\n\t\t\t}\n\t\t\tnames[uniqueName] = idx\n\t\t\tif primary {\n\t\t\t\tt.PrimaryKey = idx\n\t\t\t} else {\n\t\t\t\tt.Indexes = append(t.Indexes, idx)\n\t\t\t}\n\t\t}\n\t\tpart := &schema.IndexPart{SeqNo: len(idx.Parts) + 1, Desc: strings.Contains(createStmt, \"DESC\")}\n\t\tswitch {\n\t\tcase sqlx.ValidString(column):\n\t\t\tpart.C, ok = t.Column(column.String)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"cockroach: column %q was not found for index %q\", column.String, idx.Name)\n\t\t\t}\n\t\t\tpart.C.Indexes = append(part.C.Indexes, idx)\n\t\tcase sqlx.ValidString(expr):\n\t\t\tpart.X = &schema.RawExpr{\n\t\t\t\tX: expr.String,\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"cockroach: invalid part for index %q\", idx.Name)\n\t\t}\n\t\tidx.Parts = append(idx.Parts, part)\n\t}\n\treturn nil\n}\n\n// CockroachDB types that are not part of PostgreSQL.\nconst (\n\tTypeInt64    = \"int64\"\n\tTypeGeometry = \"geometry\"\n)\n\nconst (\n\t// CockroachDB query for getting schema indexes.\n\t// Scanning constraints is disabled due to internal CockroachDB error.\n\t// (internal error: unexpected type *tree.DOidWrapper for key value)\n\tcrdbIndexesQuery = `\nSELECT\n\tt.relname AS table_name,\n\ti.relname AS index_name,\n\ta.attname AS column_name,\n\tidx.indisprimary AS primary,\n\tidx.indisunique AS unique,\n\tNULL AS constraints,\n\tpgi.indexdef create_stmt,\n\tpg_get_expr(idx.indpred, idx.indrelid) AS predicate,\n\tpg_get_indexdef(idx.indexrelid, idx.ord, false) AS expression,\n\tpg_catalog.obj_description(i.oid, 'pg_class') AS comment\n\tFROM\n\t(\n\t\tselect\n\t\t\t*,\n\t\t\tgenerate_series(1,array_length(i.indkey,1)) as ord,\n\t\t\tunnest(i.indkey) AS key\n\t\tfrom pg_index i\n\t) idx\n\tJOIN pg_class i ON i.oid = idx.indexrelid\n\tJOIN pg_class t ON t.oid = idx.indrelid\n\tJOIN pg_namespace n ON n.oid = t.relnamespace\n\tLEFT JOIN pg_indexes pgi ON pgi.tablename = t.relname AND indexname = i.relname AND n.nspname = pgi.schemaname\n\tLEFT JOIN pg_attribute a ON (a.attrelid, a.attnum) = (idx.indrelid, idx.key)\nWHERE\n\tn.nspname = $1\n\tAND t.relname IN (%s)\nORDER BY\n\ttable_name, index_name, idx.ord\n`\n\n\tcrdbColumnsQuery = `\nSELECT\n\tt1.table_name,\n\tt1.column_name,\n\tt1.data_type,\n\tpg_catalog.format_type(a.atttypid, a.atttypmod) AS format_type,\n\tt1.is_nullable,\n\tt1.column_default,\n\tt1.character_maximum_length,\n\tt1.numeric_precision,\n\tt1.datetime_precision,\n\tt1.numeric_scale,\n\tt1.interval_type,\n\tt1.character_set_name,\n\tt1.collation_name,\n\tt1.is_identity,\n\tt5.start_value as identity_start,\n\tt5.increment_by as identity_increment,\n\tt5.last_value AS identity_last,\n\tt1.identity_generation,\n\tt1.generation_expression,\n\tcol_description(t3.oid, \"ordinal_position\") AS comment,\n\tt4.typtype,\n\tt4.typelem,\n\tt4.oid,\n\ta.attnum\nFROM\n\t\"information_schema\".\"columns\" AS t1\n\tJOIN pg_catalog.pg_namespace AS t2 ON t2.nspname = t1.table_schema\n\tJOIN pg_catalog.pg_class AS t3 ON t3.relnamespace = t2.oid AND t3.relname = t1.table_name\n\tJOIN pg_catalog.pg_attribute AS a ON a.attrelid = t3.oid AND a.attname = t1.column_name\n\tLEFT JOIN pg_catalog.pg_type AS t4\n\tON t1.udt_name = t4.typname\n\tLEFT JOIN pg_sequences AS t5\n\tON quote_ident(t5.schemaname) || '.' || quote_ident(t5.sequencename) = btrim(btrim(t1.column_default, 'nextval('''), '''::REGCLASS)')\nWHERE\n\tt1.table_schema = $1 AND t1.table_name IN (%s)\nORDER BY\n\tt1.table_name, t1.ordinal_position\n`\n)\n"
  },
  {
    "path": "sql/postgres/diff_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// DefaultDiff provides basic diffing capabilities for PostgreSQL dialects.\n// Note, it is recommended to call Open, create a new Driver and use its Differ\n// when a database connection is available.\nvar DefaultDiff schema.Differ = &sqlx.Diff{DiffDriver: &diff{&conn{ExecQuerier: sqlx.NoRows}}}\n\n// A diff provides a PostgreSQL implementation for sqlx.DiffDriver.\ntype diff struct{ *conn }\n\n// SupportChange reports if the change is supported by the differ.\nfunc (*diff) SupportChange(c schema.Change) bool {\n\tswitch c.(type) {\n\tcase *schema.RenameConstraint:\n\t\treturn false\n\t}\n\treturn true\n}\n\n// SchemaAttrDiff returns a changeset for migrating schema attributes from one state to the other.\nfunc (d *diff) SchemaAttrDiff(from, to *schema.Schema) []schema.Change {\n\tvar (\n\t\tchanges    []schema.Change\n\t\tfromA, toA []schema.Attr\n\t)\n\t// In schema scope, users might compare a \"public\" schema with a \"non-public\" schema.\n\t// However, since the public standard comment is auto created and not set by the users\n\t// this is unintentional in most cases, and this change will be rejected by the plan stage.\n\tif d.schema != \"\" {\n\t\tfromA, toA = skipDefaultComment(from, from.Name), skipDefaultComment(to, to.Name)\n\t} else {\n\t\tfromA, toA = skipDefaultComment(from, \"public\"), skipDefaultComment(to, \"public\")\n\t}\n\tif change := sqlx.CommentDiff(fromA, toA); change != nil {\n\t\tchanges = append(changes, change)\n\t}\n\treturn changes\n}\n\nfunc skipDefaultComment(s *schema.Schema, public string) []schema.Attr {\n\tattrs := s.Attrs\n\tif c := (schema.Comment{}); sqlx.Has(attrs, &c) && c.Text == \"standard public schema\" && (s.Name == \"\" || s.Name == public) {\n\t\tattrs = schema.RemoveAttr[*schema.Comment](attrs)\n\t}\n\treturn attrs\n}\n\n// TableAttrDiff returns a changeset for migrating table attributes from one state to the other.\nfunc (d *diff) TableAttrDiff(from, to *schema.Table, opts *schema.DiffOptions) ([]schema.Change, error) {\n\tvar changes []schema.Change\n\tif change := sqlx.CommentDiff(from.Attrs, to.Attrs); change != nil {\n\t\tchanges = append(changes, change)\n\t}\n\tif err := d.partitionChanged(from, to); err != nil {\n\t\treturn nil, err\n\t}\n\tchange, err := d.tableAttrDiff(from, to)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tchanges = append(changes, change...)\n\treturn append(changes, sqlx.CheckDiffMode(from, to, opts.Mode, func(c1, c2 *schema.Check) bool {\n\t\treturn sqlx.Has(c1.Attrs, &NoInherit{}) == sqlx.Has(c2.Attrs, &NoInherit{})\n\t})...), nil\n}\n\n// ColumnChange returns the schema changes (if any) for migrating one column to the other.\nfunc (d *diff) ColumnChange(_ *schema.Table, from, to *schema.Column, _ *schema.DiffOptions) (schema.Change, error) {\n\tchange := sqlx.CommentChange(from.Attrs, to.Attrs)\n\tif from.Type.Null != to.Type.Null {\n\t\tchange |= schema.ChangeNull\n\t}\n\tchanged, err := d.typeChanged(from, to)\n\tif err != nil {\n\t\treturn sqlx.NoChange, err\n\t}\n\tif changed {\n\t\tchange |= schema.ChangeType\n\t}\n\tif changed, err = d.defaultChanged(from, to); err != nil {\n\t\treturn sqlx.NoChange, err\n\t}\n\tif changed {\n\t\tchange |= schema.ChangeDefault\n\t}\n\tif identityChanged(from.Attrs, to.Attrs) {\n\t\tchange |= schema.ChangeAttr\n\t}\n\tif changed, err = d.generatedChanged(from, to); err != nil {\n\t\treturn sqlx.NoChange, err\n\t}\n\tif changed {\n\t\tchange |= schema.ChangeGenerated\n\t}\n\tif change.Is(schema.NoChange) {\n\t\treturn sqlx.NoChange, nil\n\t}\n\treturn &schema.ModifyColumn{\n\t\tChange: change,\n\t\tFrom:   from,\n\t\tTo:     to,\n\t}, nil\n}\n\n// defaultChanged reports if the default value of a column was changed.\nfunc (d *diff) defaultChanged(from, to *schema.Column) (bool, error) {\n\td1, ok1 := sqlx.DefaultValue(from)\n\td2, ok2 := sqlx.DefaultValue(to)\n\tif ok1 != ok2 {\n\t\treturn true, nil\n\t}\n\tif !ok1 && !ok2 || trimCast(d1) == trimCast(d2) || quote(d1) == quote(d2) {\n\t\treturn false, nil\n\t}\n\tvar (\n\t\t_, fromX = from.Default.(*schema.RawExpr)\n\t\t_, toX   = to.Default.(*schema.RawExpr)\n\t)\n\t// In case one of the DEFAULT values is an expression, and a database connection is\n\t// available (not DefaultDiff), we use the database to compare in case of mismatch.\n\t//\n\t//\tSELECT ARRAY[1] = '{1}'::int[]\n\t//\tSELECT lower('X'::text) = lower('X')\n\t//\n\tif (fromX || toX) && d.conn.ExecQuerier != nil && d.conn.ExecQuerier != sqlx.NoRows {\n\t\tequals, err := d.defaultEqual(from.Default, to.Default)\n\t\treturn !equals, err\n\t}\n\treturn true, nil\n}\n\n// generatedChanged reports if the generated expression of a column was changed.\nfunc (*diff) generatedChanged(from, to *schema.Column) (bool, error) {\n\tvar fromX, toX schema.GeneratedExpr\n\tswitch fromHas, toHas := sqlx.Has(from.Attrs, &fromX), sqlx.Has(to.Attrs, &toX); {\n\tcase fromHas && toHas && sqlx.MayWrap(fromX.Expr) != sqlx.MayWrap(toX.Expr):\n\t\treturn false, fmt.Errorf(\"changing the generation expression for a column %q is not supported\", from.Name)\n\tcase !fromHas && toHas:\n\t\treturn false, fmt.Errorf(\"changing column %q to generated column is not supported (drop and add is required)\", from.Name)\n\tdefault:\n\t\t// Only DROP EXPRESSION is supported.\n\t\treturn fromHas && !toHas, nil\n\t}\n}\n\n// partitionChanged checks and returns an error if the partition key of a table was changed.\nfunc (*diff) partitionChanged(from, to *schema.Table) error {\n\tvar fromP, toP Partition\n\tswitch fromHas, toHas := sqlx.Has(from.Attrs, &fromP), sqlx.Has(to.Attrs, &toP); {\n\tcase fromHas && !toHas:\n\t\treturn fmt.Errorf(\"partition key cannot be dropped from %q (drop and add is required)\", from.Name)\n\tcase !fromHas && toHas:\n\t\treturn fmt.Errorf(\"partition key cannot be added to %q (drop and add is required)\", to.Name)\n\tcase fromHas && toHas:\n\t\ts1, err := formatPartition(fromP)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts2, err := formatPartition(toP)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif s1 != s2 {\n\t\t\treturn fmt.Errorf(\"partition key of table %q cannot be changed from %s to %s (drop and add is required)\", to.Name, s1, s2)\n\t\t}\n\t}\n\treturn nil\n}\n\n// IsGeneratedIndexName reports if the index name was generated by the database.\nfunc (d *diff) IsGeneratedIndexName(t *schema.Table, idx *schema.Index) bool {\n\tnames := make([]string, len(idx.Parts))\n\tfor i, p := range idx.Parts {\n\t\tif p.C == nil {\n\t\t\treturn false\n\t\t}\n\t\tnames[i] = p.C.Name\n\t}\n\t// Auto-generate index names will have the following format: <table>_<c1>_..._key.\n\t// In case of conflict, PostgreSQL adds additional index at the end (e.g. \"key1\").\n\tp := fmt.Sprintf(\"%s_%s_key\", t.Name, strings.Join(names, \"_\"))\n\tif idx.Name == p {\n\t\treturn true\n\t}\n\ti, err := strconv.ParseInt(strings.TrimPrefix(idx.Name, p), 10, 64)\n\treturn err == nil && i > 0\n}\n\n// IndexAttrChanged reports if the index attributes were changed.\n// The default type is BTREE if no type was specified.\nfunc (*diff) IndexAttrChanged(from, to []schema.Attr) bool {\n\tt1 := &IndexType{T: IndexTypeBTree}\n\tif sqlx.Has(from, t1) {\n\t\tt1.T = strings.ToUpper(t1.T)\n\t}\n\tt2 := &IndexType{T: IndexTypeBTree}\n\tif sqlx.Has(to, t2) {\n\t\tt2.T = strings.ToUpper(t2.T)\n\t}\n\tif t1.T != t2.T {\n\t\treturn true\n\t}\n\tif indexNullsDistinct(to) != indexNullsDistinct(from) {\n\t\treturn true\n\t}\n\tif uniqueConstChanged(from, to) || excludeConstChanged(from, to) {\n\t\treturn true\n\t}\n\tvar p1, p2 IndexPredicate\n\tif sqlx.Has(from, &p1) != sqlx.Has(to, &p2) || (p1.P != p2.P && p1.P != sqlx.MayWrap(p2.P)) {\n\t\treturn true\n\t}\n\tif indexIncludeChanged(from, to) {\n\t\treturn true\n\t}\n\ts1, ok1 := indexStorageParams(from)\n\ts2, ok2 := indexStorageParams(to)\n\treturn ok1 != ok2 || ok1 && *s1 != *s2\n}\n\n// IndexPartAttrChanged reports if the index-part attributes were changed.\nfunc (*diff) IndexPartAttrChanged(fromI, toI *schema.Index, i int) bool {\n\tfrom, to := fromI.Parts[i], toI.Parts[i]\n\tp1 := &IndexColumnProperty{NullsFirst: from.Desc, NullsLast: !from.Desc}\n\tsqlx.Has(from.Attrs, p1)\n\tp2 := &IndexColumnProperty{NullsFirst: to.Desc, NullsLast: !to.Desc}\n\tsqlx.Has(to.Attrs, p2)\n\tif p1.NullsFirst != p2.NullsFirst || p1.NullsLast != p2.NullsLast {\n\t\treturn true\n\t}\n\t_, ok1 := excludeConst(from.Attrs)\n\t_, ok2 := excludeConst(to.Attrs)\n\tif ok1 && ok2 {\n\t\t// In case the index(es) are EXCLUDE constraint, we compare its operator\n\t\t// (and not its class) because the class is derived from the operator.\n\t\treturn sqlx.AttrOr(from.Attrs, &Operator{}).Name != sqlx.AttrOr(to.Attrs, &Operator{}).Name\n\t}\n\t// Op class for non-exclude.\n\tvar fromOp, toOp IndexOpClass\n\tswitch fromHas, toHas := sqlx.Has(from.Attrs, &fromOp), sqlx.Has(to.Attrs, &toOp); {\n\tcase fromHas && toHas:\n\t\treturn !fromOp.Equal(&toOp)\n\tcase toHas:\n\t\t// Report a change if a non-default operator class was added.\n\t\td, err := toOp.DefaultFor(toI, toI.Parts[i])\n\t\treturn !d && err == nil\n\tcase fromHas:\n\t\t// Report a change if a non-default operator class was removed.\n\t\td, err := fromOp.DefaultFor(fromI, fromI.Parts[i])\n\t\treturn !d && err == nil\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// ReferenceChanged reports if the foreign key referential action was changed.\nfunc (*diff) ReferenceChanged(from, to schema.ReferenceOption) bool {\n\t// According to PostgreSQL, the NO ACTION rule is set\n\t// if no referential action was defined in foreign key.\n\tif from == \"\" {\n\t\tfrom = schema.NoAction\n\t}\n\tif to == \"\" {\n\t\tto = schema.NoAction\n\t}\n\treturn from != to\n}\n\n// ForeignKeyAttrChanged reports if any of the foreign-key attributes were changed.\nfunc (*diff) ForeignKeyAttrChanged(_, _ []schema.Attr) bool {\n\treturn false\n}\n\n// DiffOptions defines PostgreSQL specific schema diffing process.\ntype DiffOptions struct {\n\tConcurrentIndex struct {\n\t\tDrop bool `spec:\"drop\"`\n\t\t// Allow config \"CREATE\" both with \"add\" and \"create\"\n\t\t// as the documentation used both terms (accidentally).\n\t\tAdd    bool `spec:\"add\"`\n\t\tCreate bool `spec:\"create\"`\n\t} `spec:\"concurrent_index\"`\n}\n\n// AnnotateChanges implements the sqlx.ChangeAnnotator interface.\nfunc (*diff) AnnotateChanges(changes []schema.Change, opts *schema.DiffOptions) ([]schema.Change, error) {\n\tvar extra DiffOptions\n\tswitch ex := opts.Extra.(type) {\n\tcase nil:\n\t\treturn changes, nil\n\tcase schemahcl.DefaultExtension:\n\t\tif err := ex.Extra.As(&extra); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"postgres: unexpected DiffOptions.Extra type %T\", opts.Extra)\n\t}\n\tfor _, c := range changes {\n\t\tm, ok := c.(*schema.ModifyTable)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tfor i := range m.Changes {\n\t\t\tswitch c := m.Changes[i].(type) {\n\t\t\tcase *schema.AddIndex:\n\t\t\t\tif extra.ConcurrentIndex.Add || extra.ConcurrentIndex.Create {\n\t\t\t\t\tc.Extra = append(c.Extra, &Concurrently{})\n\t\t\t\t}\n\t\t\tcase *schema.DropIndex:\n\t\t\t\tif extra.ConcurrentIndex.Drop {\n\t\t\t\t\tc.Extra = append(c.Extra, &Concurrently{})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn changes, nil\n}\n\nfunc (d *diff) typeChanged(from, to *schema.Column) (bool, error) {\n\treturn typeChanged(from, to, d.conn.schema)\n}\n\nfunc typeChanged(from, to *schema.Column, ns string) (bool, error) {\n\tfromT, toT := from.Type.Type, to.Type.Type\n\tif fromT == nil || toT == nil {\n\t\treturn false, fmt.Errorf(\"postgres: missing type information for column %q\", from.Name)\n\t}\n\tif reflect.TypeOf(fromT) != reflect.TypeOf(toT) {\n\t\treturn true, nil\n\t}\n\tvar changed bool\n\tswitch fromT := fromT.(type) {\n\tcase *schema.BinaryType, *BitType, *schema.BoolType, *schema.DecimalType, *schema.FloatType, *IntervalType,\n\t\t*schema.IntegerType, *schema.JSONType, *OIDType, *RangeType, *SerialType, *schema.SpatialType,\n\t\t*schema.StringType, *PseudoType, *schema.TimeType, *TextSearchType, *NetworkType, *schema.UUIDType:\n\t\tt1, err := FormatType(toT)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tt2, err := FormatType(fromT)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tchanged = t1 != t2\n\tcase *UserDefinedType:\n\t\ttoT := toT.(*UserDefinedType)\n\t\tchanged = toT.T != fromT.T &&\n\t\t\t// In case the type is defined with schema qualifier, but returned without\n\t\t\t// (inspecting a schema scope), or vice versa, remove before comparing.\n\t\t\tns != \"\" && trimSchema(toT.T, ns) != trimSchema(toT.T, ns)\n\tcase *CompositeType:\n\t\ttoT := toT.(*CompositeType)\n\t\tchanged = toT.T != fromT.T ||\n\t\t\t(toT.Schema != nil && fromT.Schema != nil && toT.Schema.Name != fromT.Schema.Name)\n\tcase *DomainType:\n\t\ttoT := toT.(*DomainType)\n\t\tchanged = toT.T != fromT.T ||\n\t\t\t(toT.Schema != nil && fromT.Schema != nil && toT.Schema.Name != fromT.Schema.Name)\n\tcase *schema.EnumType:\n\t\ttoT := toT.(*schema.EnumType)\n\t\t// Column type was changed if the underlying enum type was changed.\n\t\tchanged = fromT.T != toT.T || (toT.Schema != nil && fromT.Schema != nil && fromT.Schema.Name != toT.Schema.Name)\n\tcase *CurrencyType:\n\t\ttoT := toT.(*CurrencyType)\n\t\tchanged = fromT.T != toT.T\n\tcase *XMLType:\n\t\ttoT := toT.(*XMLType)\n\t\tchanged = fromT.T != toT.T\n\tcase *ArrayType:\n\t\ttoT := toT.(*ArrayType)\n\t\t// In case the desired schema is not normalized, the string type can look different even\n\t\t// if the two strings represent the same array type (varchar(1), character varying (1)).\n\t\t// Therefore, we try by comparing the underlying types if they were defined.\n\t\tif fromT.Type != nil && toT.Type != nil {\n\t\t\tt1, err := FormatType(fromT.Type)\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tt2, err := FormatType(toT.Type)\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\t// Same underlying type.\n\t\t\tchanged = t1 != t2\n\t\t}\n\tdefault:\n\t\treturn false, &sqlx.UnsupportedTypeError{Type: fromT}\n\t}\n\treturn changed, nil\n}\n\n// trimSchema returns the given type without the schema qualifier.\nfunc trimSchema(t string, ns string) string {\n\tif strings.HasPrefix(t, `\"`) {\n\t\treturn strings.TrimPrefix(t, fmt.Sprintf(\"%q.\", ns))\n\t}\n\treturn strings.TrimPrefix(t, fmt.Sprintf(\"%s.\", ns))\n}\n\n// defaultEqual reports if the DEFAULT values x and y\n// equal according to the database engine.\nfunc (d *diff) defaultEqual(from, to schema.Expr) (bool, error) {\n\tvar (\n\t\tb      bool\n\t\td1, d2 string\n\t)\n\tswitch from := from.(type) {\n\tcase *schema.Literal:\n\t\td1 = quote(from.V)\n\tcase *schema.RawExpr:\n\t\td1 = from.X\n\t}\n\tswitch to := to.(type) {\n\tcase *schema.Literal:\n\t\td2 = quote(to.V)\n\tcase *schema.RawExpr:\n\t\td2 = to.X\n\t}\n\t// The DEFAULT expressions are safe to be inlined in the SELECT\n\t// statement same as we inline them in the CREATE TABLE statement.\n\trows, err := d.QueryContext(context.Background(), fmt.Sprintf(\"SELECT %s = %s\", d1, d2))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif err := sqlx.ScanOne(rows, &b); err != nil {\n\t\treturn false, err\n\t}\n\treturn b, nil\n}\n\n// Default IDENTITY attributes.\nconst (\n\tdefaultIdentityGen  = \"BY DEFAULT\"\n\tdefaultSeqStart     = 1\n\tdefaultSeqIncrement = 1\n)\n\n// identityChanged reports if one of the identity attributes was changed.\nfunc identityChanged(from, to []schema.Attr) bool {\n\ti1, ok1 := identity(from)\n\ti2, ok2 := identity(to)\n\tif !ok1 && !ok2 || ok1 != ok2 {\n\t\treturn ok1 != ok2\n\t}\n\treturn i1.Generation != i2.Generation || i1.Sequence.Start != i2.Sequence.Start || i1.Sequence.Increment != i2.Sequence.Increment\n}\n\nfunc identity(attrs []schema.Attr) (*Identity, bool) {\n\ti := &Identity{}\n\tif !sqlx.Has(attrs, i) {\n\t\treturn nil, false\n\t}\n\tif i.Generation == \"\" {\n\t\ti.Generation = defaultIdentityGen\n\t}\n\tif i.Sequence == nil {\n\t\ti.Sequence = &Sequence{Start: defaultSeqStart, Increment: defaultSeqIncrement}\n\t\treturn i, true\n\t}\n\tif i.Sequence.Start == 0 {\n\t\ti.Sequence.Start = defaultSeqStart\n\t}\n\tif i.Sequence.Increment == 0 {\n\t\ti.Sequence.Increment = defaultSeqIncrement\n\t}\n\treturn i, true\n}\n\n// formatPartition returns the string representation of the\n// partition key according to the PostgreSQL format/grammar.\nfunc formatPartition(p Partition) (string, error) {\n\tb := &sqlx.Builder{QuoteOpening: '\"', QuoteClosing: '\"'}\n\tb.P(\"PARTITION BY\")\n\tswitch t := strings.ToUpper(p.T); t {\n\tcase PartitionTypeRange, PartitionTypeList, PartitionTypeHash:\n\t\tb.P(t)\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unknown partition type: %q\", t)\n\t}\n\tif len(p.Parts) == 0 {\n\t\treturn \"\", errors.New(\"missing parts for partition key\")\n\t}\n\tb.Wrap(func(b *sqlx.Builder) {\n\t\tb.MapComma(p.Parts, func(i int, b *sqlx.Builder) {\n\t\t\tswitch k := p.Parts[i]; {\n\t\t\tcase k.C != nil:\n\t\t\t\tb.Ident(k.C.Name)\n\t\t\tcase k.X != nil:\n\t\t\t\tb.P(sqlx.MayWrap(k.X.(*schema.RawExpr).X))\n\t\t\t}\n\t\t})\n\t})\n\treturn b.String(), nil\n}\n\n// indexStorageParams returns the index storage parameters from the attributes\n// in case it is there, and it is not the default.\nfunc indexStorageParams(attrs []schema.Attr) (*IndexStorageParams, bool) {\n\ts := &IndexStorageParams{}\n\tif !sqlx.Has(attrs, s) {\n\t\treturn nil, false\n\t}\n\tif !s.AutoSummarize && (s.PagesPerRange == 0 || s.PagesPerRange == defaultPagesPerRange) {\n\t\treturn nil, false\n\t}\n\treturn s, true\n}\n\n// indexIncludeChanged reports if the INCLUDE attribute clause was changed.\nfunc indexIncludeChanged(from, to []schema.Attr) bool {\n\tvar fromI, toI IndexInclude\n\tif sqlx.Has(from, &fromI) != sqlx.Has(to, &toI) || len(fromI.Columns) != len(toI.Columns) {\n\t\treturn true\n\t}\n\tfor i := range fromI.Columns {\n\t\tif fromI.Columns[i].Name != toI.Columns[i].Name {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// indexNullsDistinct returns the NULLS [NOT] DISTINCT value from the index attributes.\nfunc indexNullsDistinct(attrs []schema.Attr) bool {\n\tif i := (IndexNullsDistinct{}); sqlx.Has(attrs, &i) {\n\t\treturn i.V\n\t}\n\t// The default PostgreSQL behavior. The inverse of\n\t// \"indnullsnotdistinct\" in pg_index which is false.\n\treturn true\n}\n\n// uniqueConst returns the first unique constraint from the given attributes.\nfunc uniqueConst(attrs []schema.Attr) (*Constraint, bool) {\n\tfor _, a := range attrs {\n\t\tif c, ok := a.(*Constraint); ok && c.IsUnique() {\n\t\t\treturn c, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// excludeConst returns the first exclude constraint from the given attributes.\nfunc excludeConst(attrs []schema.Attr) (*Constraint, bool) {\n\tfor _, a := range attrs {\n\t\tif c, ok := a.(*Constraint); ok && c.IsExclude() {\n\t\t\treturn c, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\nfunc trimCast(s string) string {\n\ti := strings.LastIndex(s, \"::\")\n\tif i == -1 {\n\t\treturn s\n\t}\n\tfor _, r := range s[i+2:] {\n\t\tif r != ' ' && !unicode.IsLetter(r) {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn s[:i]\n}\n"
  },
  {
    "path": "sql/postgres/diff_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDiff_TableDiff(t *testing.T) {\n\ttype testcase struct {\n\t\tname        string\n\t\tfrom, to    *schema.Table\n\t\twantChanges []schema.Change\n\t\twantErr     bool\n\t}\n\ttests := []testcase{\n\t\t{\n\t\t\tname: \"no changes\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\tto:   &schema.Table{Name: \"users\"},\n\t\t},\n\t\t{\n\t\t\tname: \"change identity attributes\",\n\t\t\tfrom: func() *schema.Table {\n\t\t\t\tt := &schema.Table{\n\t\t\t\t\tName: \"users\",\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tt.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: t.Columns[0]}}}\n\t\t\t\treturn t\n\t\t\t}(),\n\t\t\tto: func() *schema.Table {\n\t\t\t\tt := &schema.Table{\n\t\t\t\t\tName: \"users\",\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}, Attrs: []schema.Attr{&Identity{Sequence: &Sequence{Start: 1024, Increment: 1}}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tt.PrimaryKey = &schema.Index{Parts: []*schema.IndexPart{{C: t.Columns[0]}}}\n\t\t\t\treturn t\n\t\t\t}(),\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\tFrom:   &schema.Column{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\tTo:     &schema.Column{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}, Attrs: []schema.Attr{&Identity{Sequence: &Sequence{Start: 1024, Increment: 1}}}},\n\t\t\t\t\tChange: schema.ChangeAttr,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"drop partition key\",\n\t\t\tfrom: schema.NewTable(\"logs\").\n\t\t\t\tAddAttrs(&Partition{\n\t\t\t\t\tT:     PartitionTypeRange,\n\t\t\t\t\tParts: []*PartitionPart{{C: schema.NewColumn(\"c\")}},\n\t\t\t\t}),\n\t\t\tto:      schema.NewTable(\"logs\"),\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"add partition key\",\n\t\t\tfrom: schema.NewTable(\"logs\"),\n\t\t\tto: schema.NewTable(\"logs\").\n\t\t\t\tAddAttrs(&Partition{\n\t\t\t\t\tT:     PartitionTypeRange,\n\t\t\t\t\tParts: []*PartitionPart{{C: schema.NewColumn(\"c\")}},\n\t\t\t\t}),\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"change partition key column\",\n\t\t\tfrom: schema.NewTable(\"logs\").\n\t\t\t\tAddAttrs(&Partition{\n\t\t\t\t\tT:     PartitionTypeRange,\n\t\t\t\t\tParts: []*PartitionPart{{C: schema.NewColumn(\"c\")}},\n\t\t\t\t}),\n\t\t\tto: schema.NewTable(\"logs\").\n\t\t\t\tAddAttrs(&Partition{\n\t\t\t\t\tT:     PartitionTypeRange,\n\t\t\t\t\tParts: []*PartitionPart{{C: schema.NewColumn(\"d\")}},\n\t\t\t\t}),\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"change partition key type\",\n\t\t\tfrom: schema.NewTable(\"logs\").\n\t\t\t\tAddAttrs(&Partition{\n\t\t\t\t\tT:     PartitionTypeRange,\n\t\t\t\t\tParts: []*PartitionPart{{C: schema.NewColumn(\"c\")}},\n\t\t\t\t}),\n\t\t\tto: schema.NewTable(\"logs\").\n\t\t\t\tAddAttrs(&Partition{\n\t\t\t\t\tT:     PartitionTypeHash,\n\t\t\t\t\tParts: []*PartitionPart{{C: schema.NewColumn(\"c\")}},\n\t\t\t\t}),\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tname: \"add check\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\tto:   &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&schema.Check{Name: \"t1_c1_check\", Expr: \"(c1 > 1)\"}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.AddCheck{\n\t\t\t\t\tC: &schema.Check{Name: \"t1_c1_check\", Expr: \"(c1 > 1)\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"drop check\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&schema.Check{Name: \"t1_c1_check\", Expr: \"(c1 > 1)\"}}},\n\t\t\tto:   &schema.Table{Name: \"t1\"},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.DropCheck{\n\t\t\t\t\tC: &schema.Check{Name: \"t1_c1_check\", Expr: \"(c1 > 1)\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"add comment\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\tto:   &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&schema.Comment{Text: \"t1\"}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.AddAttr{\n\t\t\t\t\tA: &schema.Comment{Text: \"t1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"drop comment\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&schema.Comment{Text: \"t1\"}}},\n\t\t\tto:   &schema.Table{Name: \"t1\"},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Comment{Text: \"t1\"},\n\t\t\t\t\tTo:   &schema.Comment{Text: \"\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"modify comment\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}, Attrs: []schema.Attr{&schema.Comment{Text: \"t1\"}}},\n\t\t\tto:   &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&schema.Comment{Text: \"t1!\"}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Comment{Text: \"t1\"},\n\t\t\t\t\tTo:   &schema.Comment{Text: \"t1!\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\ts    = schema.New(\"public\")\n\t\t\t\tfrom = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(s).\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t)\n\t\t\t\tto = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(s).\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\"),\n\t\t\t\t\t)\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"drop generation expression\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{From: from.Columns[0], To: to.Columns[0], Change: schema.ChangeGenerated},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\t{\n\t\t\tname: \"change generation expression\",\n\t\t\tfrom: schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\").\n\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t),\n\t\t\tto: schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\").\n\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"2\", Type: \"STORED\"}),\n\t\t\t\t),\n\t\t\twantErr: true,\n\t\t},\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}},\n\t\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"int8\", Type: &schema.IntegerType{T: \"int8\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tto = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"c1\",\n\t\t\t\t\t\t\tType:    &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}, Null: true},\n\t\t\t\t\t\t\tDefault: &schema.RawExpr{X: \"{}\"},\n\t\t\t\t\t\t\tAttrs:   []schema.Attr{&schema.Comment{Text: \"json comment\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"columns\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\tFrom:   from.Columns[0],\n\t\t\t\t\t\tTo:     to.Columns[0],\n\t\t\t\t\t\tChange: schema.ChangeNull | schema.ChangeComment | schema.ChangeDefault,\n\t\t\t\t\t},\n\t\t\t\t\t&schema.DropColumn{C: from.Columns[1]},\n\t\t\t\t\t&schema.AddColumn{C: to.Columns[1]},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\t// Modify enum type or values.\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = schema.NewTable(\"users\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewEnumColumn(\"enum1\", schema.EnumName(\"enum1\"), schema.EnumValues(\"a\")),\n\t\t\t\t\t\tschema.NewEnumColumn(\"enum3\", schema.EnumName(\"enum3\"), schema.EnumValues(\"a\")),\n\t\t\t\t\t\tschema.NewEnumColumn(\"enum4\", schema.EnumName(\"enum4\"), schema.EnumValues(\"a\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t)\n\t\t\t\tto = schema.NewTable(\"users\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t// Change type.\n\t\t\t\t\t\tschema.NewEnumColumn(\"enum1\", schema.EnumName(\"enum2\"), schema.EnumValues(\"a\")),\n\t\t\t\t\t\t// No change as schema is optional.\n\t\t\t\t\t\tschema.NewEnumColumn(\"enum3\", schema.EnumName(\"enum3\"), schema.EnumValues(\"a\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t\t// Enum type was changed (reside in a different schema).\n\t\t\t\t\t\tschema.NewEnumColumn(\"enum4\", schema.EnumName(\"enum4\"), schema.EnumValues(\"a\"), schema.EnumSchema(schema.New(\"test\"))),\n\t\t\t\t\t)\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"enums\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{From: from.Columns[0], To: to.Columns[0], Change: schema.ChangeType},\n\t\t\t\t\t&schema.ModifyColumn{From: from.Columns[2], To: to.Columns[2], Change: schema.ChangeType},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\t// Modify array of type enum.\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = schema.NewTable(\"users\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewColumn(\"a1\").SetType(&ArrayType{T: \"state[]\", Type: &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\"}}}),\n\t\t\t\t\t\tschema.NewColumn(\"a3\").SetType(&ArrayType{T: \"state[]\", Type: &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\"}}}),\n\t\t\t\t\t)\n\t\t\t\tto = schema.NewTable(\"users\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewColumn(\"a1\").SetType(&ArrayType{T: \"status[]\", Type: &schema.EnumType{T: \"status\", Values: []string{\"on\", \"off\"}}}),\n\t\t\t\t\t\tschema.NewColumn(\"a3\").SetType(&ArrayType{T: \"state[]\", Type: &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\"}}}),\n\t\t\t\t\t)\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"enum arrays\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{From: from.Columns[0], To: to.Columns[0], Change: schema.ChangeType},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}, Default: &schema.RawExpr{X: \"'{}'\"}},\n\t\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"int8\", Type: &schema.IntegerType{T: \"int8\"}}},\n\t\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tto = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}, Default: &schema.RawExpr{X: \"'{}'::json\"}},\n\t\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"int8\", Type: &schema.IntegerType{T: \"int8\"}}},\n\t\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t)\n\t\t\tfrom.Indexes = []*schema.Index{\n\t\t\t\t{Name: \"c1_index\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[0]}}},\n\t\t\t\t{Name: \"c2_unique\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}},\n\t\t\t\t{Name: \"c3_predicate\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}},\n\t\t\t\t{Name: \"c4_predicate\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexPredicate{P: \"(c4 <> NULL)\"}}},\n\t\t\t\t{Name: \"c4_storage_params\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexStorageParams{PagesPerRange: 4}}},\n\t\t\t\t{Name: \"c5_include_no_change\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexInclude{Columns: from.Columns[:1]}}},\n\t\t\t\t{Name: \"c5_include_added\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}},\n\t\t\t\t{Name: \"c5_include_dropped\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexInclude{Columns: from.Columns[:1]}}},\n\t\t\t\t{Name: \"c6_nulls_not_distinct\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexNullsDistinct{V: true}}},\n\t\t\t}\n\t\t\tto.Indexes = []*schema.Index{\n\t\t\t\t{Name: \"c1_index\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[0]}}},\n\t\t\t\t{Name: \"c3_unique\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: to.Columns[1]}}},\n\t\t\t\t{Name: \"c3_predicate\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexPredicate{P: \"c3 <> NULL\"}}},\n\t\t\t\t{Name: \"c4_predicate\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexPredicate{P: \"c4 <> NULL\"}}},\n\t\t\t\t{Name: \"c4_storage_params\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexStorageParams{PagesPerRange: 2}}},\n\t\t\t\t{Name: \"c5_include_no_change\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexInclude{Columns: from.Columns[:1]}}},\n\t\t\t\t{Name: \"c5_include_added\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexInclude{Columns: from.Columns[:1]}}},\n\t\t\t\t{Name: \"c5_include_dropped\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}},\n\t\t\t\t{Name: \"c6_nulls_not_distinct\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexNullsDistinct{V: false}}},\n\t\t\t}\n\t\t\treturn testcase{\n\t\t\t\tname: \"indexes\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[0], To: to.Indexes[0], Change: schema.ChangeUnique},\n\t\t\t\t\t&schema.DropIndex{I: from.Indexes[1]},\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[2], To: to.Indexes[2], Change: schema.ChangeAttr},\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[4], To: to.Indexes[4], Change: schema.ChangeAttr},\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[6], To: to.Indexes[6], Change: schema.ChangeAttr},\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[7], To: to.Indexes[7], Change: schema.ChangeAttr},\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[8], To: to.Indexes[8], Change: schema.ChangeAttr},\n\t\t\t\t\t&schema.AddIndex{I: to.Indexes[1]},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tAddColumns(schema.NewIntColumn(\"c1\", \"int8\"))\n\t\t\t\tto = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\tAddColumns(schema.NewIntColumn(\"c1\", \"int8\"))\n\t\t\t)\n\t\t\tfrom.Indexes = []*schema.Index{\n\t\t\t\tschema.NewIndex(\"idx1\").AddParts(schema.NewColumnPart(from.Columns[0])),\n\t\t\t\tschema.NewIndex(\"idx2\").AddParts(schema.NewColumnPart(from.Columns[0])),\n\t\t\t\tschema.NewIndex(\"idx3\").AddParts(schema.NewColumnPart(from.Columns[0])),\n\t\t\t\tschema.NewIndex(\"idx4\").AddParts(schema.NewColumnPart(to.Columns[0]).AddAttrs(&IndexOpClass{Name: \"int8_ops\"})),\n\t\t\t\tschema.NewIndex(\"idx5\").AddParts(schema.NewColumnPart(to.Columns[0]).AddAttrs(&IndexOpClass{Name: \"int8_ops\"})),\n\t\t\t}\n\t\t\tto.Indexes = []*schema.Index{\n\t\t\t\t// A default operator class was added.\n\t\t\t\tschema.NewIndex(\"idx1\").AddParts(schema.NewColumnPart(to.Columns[0]).AddAttrs(&IndexOpClass{Name: \"int8_ops\"})),\n\t\t\t\t// Unrecognized operator class with explicit default.\n\t\t\t\tschema.NewIndex(\"idx2\").AddParts(schema.NewColumnPart(to.Columns[0]).AddAttrs(&IndexOpClass{Name: \"int8_custom\", Default: true})),\n\t\t\t\t// A default operator class but with custom parameters.\n\t\t\t\tschema.NewIndex(\"idx3\").AddParts(schema.NewColumnPart(to.Columns[0]).AddAttrs(&IndexOpClass{Name: \"int8_ops\", Params: []struct{ N, V string }{{\"signlen\", \"1\"}}})),\n\t\t\t\t// A default operator class was dropped.\n\t\t\t\tschema.NewIndex(\"idx4\").AddParts(schema.NewColumnPart(from.Columns[0])),\n\t\t\t\t// Equal operators.\n\t\t\t\tschema.NewIndex(\"idx5\").AddParts(schema.NewColumnPart(to.Columns[0]).AddAttrs(&IndexOpClass{Name: \"int8_ops\"})),\n\t\t\t}\n\t\t\treturn testcase{\n\t\t\t\tname: \"operator class\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[2], To: to.Indexes[2], Change: schema.ChangeParts},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tfrom := schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\tAddColumns(schema.NewStringColumn(\"id\", \"varchar\"), schema.NewBoolColumn(\"active\", \"bool\"))\n\t\t\tfrom.SetPrimaryKey(schema.NewPrimaryKey(from.Columns...))\n\t\t\tto := schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\tAddColumns(schema.NewStringColumn(\"id\", \"varchar\"), schema.NewBoolColumn(\"active\", \"bool\"))\n\t\t\tto.SetPrimaryKey(\n\t\t\t\tschema.NewPrimaryKey(from.Columns...).\n\t\t\t\t\tAddAttrs(&IndexPredicate{P: \"active\"}),\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"modify primary-key\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyPrimaryKey{\n\t\t\t\t\t\tFrom:   from.PrimaryKey,\n\t\t\t\t\t\tTo:     to.PrimaryKey,\n\t\t\t\t\t\tChange: schema.ChangeAttr,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tref = &schema.Table{\n\t\t\t\t\tName: \"t2\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t\t{Name: \"ref_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tfrom = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"t2_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tto = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"t2_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t)\n\t\t\tfrom.ForeignKeys = []*schema.ForeignKey{\n\t\t\t\t{Table: from, Columns: from.Columns, RefTable: ref, RefColumns: ref.Columns[:1]},\n\t\t\t}\n\t\t\tto.ForeignKeys = []*schema.ForeignKey{\n\t\t\t\t{Table: to, Columns: to.Columns, RefTable: ref, RefColumns: ref.Columns[1:]},\n\t\t\t}\n\t\t\treturn testcase{\n\t\t\t\tname: \"foreign-keys\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyForeignKey{\n\t\t\t\t\t\tFrom:   from.ForeignKeys[0],\n\t\t\t\t\t\tTo:     to.ForeignKeys[0],\n\t\t\t\t\t\tChange: schema.ChangeRefColumn,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t}\n\tfor _, tt := range tests {\n\t\tdb, m, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\t\tmock{m}.version(\"130000\")\n\t\tdrv, err := Open(db)\n\t\trequire.NoError(t, err)\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tchanges, err := drv.TableDiff(tt.from, tt.to)\n\t\t\trequire.Equalf(t, tt.wantErr, err != nil, \"got: %v\", err)\n\t\t\trequire.EqualValues(t, tt.wantChanges, changes)\n\t\t})\n\t}\n}\n\nfunc TestDiff_RealmDiff(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmock{m}.version(\"130000\")\n\tdrv, err := Open(db)\n\tto := schema.New(\"public\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").AddColumns(schema.NewIntColumn(\"t2_id\", \"int\")),\n\t\t).\n\t\tAddObjects(\n\t\t\t&schema.EnumType{T: \"e\", Values: []string{\"b\"}},\n\t\t)\n\tchanges, err := drv.RealmDiff(schema.NewRealm(), schema.NewRealm(to))\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, []schema.Change{\n\t\t&schema.AddSchema{S: to},\n\t\t&schema.AddObject{O: to.Objects[0]},\n\t\t&schema.AddTable{T: to.Tables[0]},\n\t}, changes)\n}\n\nfunc TestDiff_SchemaDiff(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmock{m}.version(\"130000\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\tfrom := schema.New(\"public\").\n\t\tAddTables(schema.NewTable(\"users\"), schema.NewTable(\"pets\")).\n\t\tAddObjects(&schema.EnumType{T: \"dropped\"}, &schema.EnumType{T: \"modified\", Values: []string{\"a\"}}, &schema.EnumType{T: \"unchanged\"})\n\tto := schema.New(\"public\").AddTables(schema.NewTable(\"users\").AddColumns(schema.NewIntColumn(\"t2_id\", \"int\")), schema.NewTable(\"groups\")).\n\t\tAddObjects(&schema.EnumType{T: \"modified\", Values: []string{\"b\"}}, &schema.EnumType{T: \"unchanged\"}, &schema.EnumType{T: \"added\"})\n\tchanges, err := drv.SchemaDiff(from, to)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, []schema.Change{\n\t\t&schema.DropObject{O: from.Objects[0]},\n\t\t&schema.ModifyObject{From: from.Objects[1], To: to.Objects[0]},\n\t\t&schema.AddObject{O: to.Objects[2]},\n\t\t&schema.ModifyTable{T: to.Tables[0], Changes: []schema.Change{&schema.AddColumn{C: to.Tables[0].Columns[0]}}},\n\t\t&schema.DropTable{T: from.Tables[1]},\n\t\t&schema.AddTable{T: to.Tables[1]},\n\t}, changes)\n\n\t// Add comment.\n\tfrom, to = schema.New(\"public\"), schema.New(\"public\").SetComment(\"comment\")\n\tchanges, err = drv.SchemaDiff(from, to)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, []schema.Change{\n\t\t&schema.ModifySchema{S: to, Changes: schema.Changes{&schema.AddAttr{A: &schema.Comment{Text: \"comment\"}}}},\n\t}, changes)\n\t// Modify comment.\n\tfrom.SetComment(\"boring\")\n\tchanges, err = drv.SchemaDiff(from, to)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, []schema.Change{\n\t\t&schema.ModifySchema{S: to, Changes: schema.Changes{\n\t\t\t&schema.ModifyAttr{\n\t\t\t\tFrom: &schema.Comment{Text: \"boring\"},\n\t\t\t\tTo:   &schema.Comment{Text: \"comment\"},\n\t\t\t},\n\t\t}},\n\t}, changes)\n\n\tt.Run(\"DefaultComment\", func(t *testing.T) {\n\t\tfrom, to := schema.New(\"public\").SetComment(\"standard public schema\"), schema.New(\"public\")\n\t\tchanges, err = drv.SchemaDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\n\t\tchanges, err = drv.SchemaDiff(to, from)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\n\t\tfrom.Name, to.Name = \"\", \"\"\n\t\tchanges, err = drv.SchemaDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\n\t\tfrom.Name, to.Name = \"other\", \"other\"\n\t\tchanges, err = drv.SchemaDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, changes, 1)\n\t\trequire.EqualValues(t, []schema.Change{\n\t\t\t&schema.ModifySchema{S: to, Changes: schema.Changes{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Comment{Text: \"standard public schema\"},\n\t\t\t\t\tTo:   &schema.Comment{Text: \"\"},\n\t\t\t\t},\n\t\t\t}},\n\t\t}, changes)\n\n\t\tfrom.Name, to.Name = \"public\", \"public\"\n\t\tfrom.SetComment(\"custom public schema\")\n\t\tchanges, err = drv.SchemaDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, []schema.Change{\n\t\t\t&schema.ModifySchema{S: to, Changes: schema.Changes{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Comment{Text: \"custom public schema\"},\n\t\t\t\t\tTo:   &schema.Comment{Text: \"\"},\n\t\t\t\t},\n\t\t\t}},\n\t\t}, changes)\n\n\t\t// In schema scope, auto created\n\t\t// public comment should be ignored.\n\t\tdrv.(*Driver).schema = \"public\"\n\t\tfrom.Name, to.Name = \"other\", \"other\"\n\t\tfrom.SetComment(\"standard public schema\")\n\t\tto.SetComment(\"standard public schema\")\n\t\tchanges, err = drv.SchemaDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\n\t\tto.SetComment(\"\")\n\t\tchanges, err = drv.SchemaDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\n\t\tfrom.Name, to.Name = \"public\", \"public\"\n\t\tchanges, err = drv.SchemaDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, changes)\n\n\t\tfrom.SetComment(\"custom public schema\")\n\t\tchanges, err = drv.SchemaDiff(from, to)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, []schema.Change{\n\t\t\t&schema.ModifySchema{S: to, Changes: schema.Changes{\n\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\tFrom: &schema.Comment{Text: \"custom public schema\"},\n\t\t\t\t\tTo:   &schema.Comment{Text: \"\"},\n\t\t\t\t},\n\t\t\t}},\n\t\t}, changes)\n\t})\n}\n\nfunc TestDefaultDiff(t *testing.T) {\n\tchanges, err := DefaultDiff.SchemaDiff(\n\t\tschema.New(\"public\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"users\").AddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t),\n\t\tschema.New(\"public\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.Len(t, changes, 1)\n\trequire.IsType(t, &schema.DropTable{}, changes[0])\n}\n\nfunc TestDiff_AnnotateChanges(t *testing.T) {\n\tvar cfg struct {\n\t\tschemahcl.DefaultExtension\n\t}\n\t// language=hcl\n\terr := schemahcl.New().EvalBytes([]byte(`\nconcurrent_index {\n  add  = true\n  drop = true\n}\n`), &cfg, nil)\n\trequire.NoError(t, err)\n\tfrom := schema.New(\"public\").AddTables(schema.NewTable(\"users\").AddIndexes(schema.NewIndex(\"users_pkey_old\").AddColumns(schema.NewIntColumn(\"id\", \"int\"))))\n\tto := schema.New(\"public\").AddTables(schema.NewTable(\"users\").AddIndexes(schema.NewIndex(\"users_pkey_new\").AddColumns(schema.NewIntColumn(\"id\", \"int\"))))\n\tchanges, err := DefaultDiff.SchemaDiff(from, to, func(opts *schema.DiffOptions) { opts.Extra = cfg.DefaultExtension })\n\trequire.NoError(t, err)\n\trequire.Len(t, changes, 1)\n\tplan, err := DefaultPlan.PlanChanges(context.Background(), \"changes\", changes)\n\trequire.NoError(t, err)\n\trequire.Len(t, plan.Changes, 2)\n\trequire.Equal(t, `DROP INDEX CONCURRENTLY \"public\".\"users_pkey_old\"`, plan.Changes[0].Cmd)\n\trequire.Equal(t, `CREATE INDEX CONCURRENTLY \"users_pkey_old\" ON \"public\".\"users\" (\"id\")`, plan.Changes[0].Reverse)\n\trequire.Equal(t, `CREATE INDEX CONCURRENTLY \"users_pkey_new\" ON \"public\".\"users\" (\"id\")`, plan.Changes[1].Cmd)\n\trequire.Equal(t, `DROP INDEX CONCURRENTLY \"public\".\"users_pkey_new\"`, plan.Changes[1].Reverse)\n}\n"
  },
  {
    "path": "sql/postgres/driver_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"math/rand\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/specutil\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t\"ariga.io/atlas/sql/sqlspec\"\n)\n\ntype (\n\t// Driver represents a PostgreSQL driver for introspecting database schemas,\n\t// generating diff between schema elements and apply migrations changes.\n\tDriver struct {\n\t\t*conn\n\t\tschema.Differ\n\t\tschema.Inspector\n\t\tmigrate.PlanApplier\n\t}\n\n\t// database connection and its information.\n\tconn struct {\n\t\tschema.ExecQuerier\n\t\t// The schema in the `search_path` parameter (if given).\n\t\tschema string\n\t\t// Maps to the connection default_table_access_method parameter.\n\t\taccessMethod string\n\t\t// System variables that are set on `Open`.\n\t\tversion int\n\t\tcrdb    bool\n\t}\n)\n\nvar _ interface {\n\tmigrate.StmtScanner\n\tschema.TypeParseFormatter\n} = (*Driver)(nil)\n\n// DriverName holds the name used for registration.\nconst DriverName = \"postgres\"\n\nfunc init() {\n\tsqlclient.Register(\n\t\tDriverName,\n\t\tsqlclient.OpenerFunc(opener),\n\t\tsqlclient.RegisterDriverOpener(Open),\n\t\tsqlclient.RegisterFlavours(\"postgresql\"),\n\t\tsqlclient.RegisterCodec(codec, codec),\n\t\tsqlclient.RegisterURLParser(parser{}),\n\t)\n}\n\nfunc opener(_ context.Context, u *url.URL) (*sqlclient.Client, error) {\n\tur := parser{}.ParseURL(u)\n\tdb, err := sql.Open(DriverName, ur.DSN)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdrv, err := Open(db)\n\tif err != nil {\n\t\tif cerr := db.Close(); cerr != nil {\n\t\t\terr = fmt.Errorf(\"%w: %v\", err, cerr)\n\t\t}\n\t\treturn nil, err\n\t}\n\tswitch drv := drv.(type) {\n\tcase *Driver:\n\t\tdrv.schema = ur.Schema\n\tcase noLockDriver:\n\t\tdrv.noLocker.(*Driver).schema = ur.Schema\n\t}\n\treturn &sqlclient.Client{\n\t\tName:   DriverName,\n\t\tDB:     db,\n\t\tURL:    ur,\n\t\tDriver: drv,\n\t}, nil\n}\n\n// Open opens a new PostgreSQL driver.\nfunc Open(db schema.ExecQuerier) (migrate.Driver, error) {\n\tc := &conn{ExecQuerier: db}\n\trows, err := db.QueryContext(context.Background(), paramsQuery)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"postgres: scanning system variables: %w\", err)\n\t}\n\tvar ver, am, crdb sql.NullString\n\tif err := sqlx.ScanOne(rows, &ver, &am, &crdb); err != nil {\n\t\treturn nil, fmt.Errorf(\"postgres: scanning system variables: %w\", err)\n\t}\n\tif c.version, err = strconv.Atoi(ver.String); err != nil {\n\t\treturn nil, fmt.Errorf(\"postgres: malformed version: %s: %w\", ver.String, err)\n\t}\n\tif c.version < 10_00_00 {\n\t\treturn nil, fmt.Errorf(\"postgres: unsupported postgres version: %d\", c.version)\n\t}\n\tc.accessMethod = am.String\n\tif c.crdb = sqlx.ValidString(crdb); c.crdb {\n\t\treturn noLockDriver{\n\t\t\t&Driver{\n\t\t\t\tconn:        c,\n\t\t\t\tDiffer:      &sqlx.Diff{DiffDriver: &crdbDiff{diff{c}}},\n\t\t\t\tInspector:   &crdbInspect{inspect{c}},\n\t\t\t\tPlanApplier: &planApply{c},\n\t\t\t},\n\t\t}, nil\n\t}\n\treturn &Driver{\n\t\tconn:        c,\n\t\tDiffer:      &sqlx.Diff{DiffDriver: &diff{c}},\n\t\tInspector:   &inspect{c},\n\t\tPlanApplier: &planApply{c},\n\t}, nil\n}\n\nfunc (d *Driver) dev() *sqlx.DevDriver {\n\treturn &sqlx.DevDriver{\n\t\tDriver: d,\n\t\tPatchObject: func(s *schema.Schema, o schema.Object) {\n\t\t\tif e, ok := o.(*schema.EnumType); ok {\n\t\t\t\te.Schema = s\n\t\t\t}\n\t\t},\n\t}\n}\n\n// NormalizeRealm returns the normal representation of the given database.\nfunc (d *Driver) NormalizeRealm(ctx context.Context, r *schema.Realm) (*schema.Realm, error) {\n\treturn d.dev().NormalizeRealm(ctx, r)\n}\n\n// NormalizeSchema returns the normal representation of the given database.\nfunc (d *Driver) NormalizeSchema(ctx context.Context, s *schema.Schema) (*schema.Schema, error) {\n\treturn d.dev().NormalizeSchema(ctx, s)\n}\n\n// Lock implements the schema.Locker interface.\nfunc (d *Driver) Lock(ctx context.Context, name string, timeout time.Duration) (schema.UnlockFunc, error) {\n\tconn, err := sqlx.SingleConn(ctx, d.ExecQuerier)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\th := fnv.New32()\n\th.Write([]byte(name))\n\tid := h.Sum32()\n\tif err := acquire(ctx, conn, id, timeout); err != nil {\n\t\tconn.Close()\n\t\treturn nil, err\n\t}\n\treturn func() error {\n\t\tdefer conn.Close()\n\t\trows, err := conn.QueryContext(ctx, \"SELECT pg_advisory_unlock($1)\", id)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch released, err := sqlx.ScanNullBool(rows); {\n\t\tcase err != nil:\n\t\t\treturn err\n\t\tcase !released.Valid || !released.Bool:\n\t\t\treturn fmt.Errorf(\"sql/postgres: failed releasing lock %d\", id)\n\t\t}\n\t\treturn nil\n\t}, nil\n}\n\n// Snapshot implements migrate.Snapshoter.\nfunc (d *Driver) Snapshot(ctx context.Context) (migrate.RestoreFunc, error) {\n\t// Postgres will only then be considered bound to a schema if the `search_path` was given.\n\t// In all other cases, the connection is considered bound to the realm.\n\tif d.schema != \"\" {\n\t\ts, err := d.InspectSchema(ctx, d.schema, nil)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif len(s.Tables) > 0 {\n\t\t\treturn nil, &migrate.NotCleanError{\n\t\t\t\tState:  schema.NewRealm(s),\n\t\t\t\tReason: fmt.Sprintf(\"found table %q in connected schema\", s.Tables[0].Name),\n\t\t\t}\n\t\t}\n\t\treturn d.SchemaRestoreFunc(s), nil\n\t}\n\t// Not bound to a schema.\n\trealm, err := d.InspectRealm(ctx, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\trestore := d.RealmRestoreFunc(realm)\n\t// Postgres is considered clean, if there are no schemas or the public schema has no tables.\n\tif len(realm.Schemas) == 0 {\n\t\treturn restore, nil\n\t}\n\tif s, ok := realm.Schema(\"public\"); len(realm.Schemas) == 1 && ok {\n\t\tif len(s.Tables) > 0 {\n\t\t\treturn nil, &migrate.NotCleanError{\n\t\t\t\tState:  realm,\n\t\t\t\tReason: fmt.Sprintf(\"found table %q in schema %q\", s.Tables[0].Name, s.Name),\n\t\t\t}\n\t\t}\n\t\treturn restore, nil\n\t}\n\treturn nil, &migrate.NotCleanError{\n\t\tState:  realm,\n\t\tReason: fmt.Sprintf(\"found schema %q\", realm.Schemas[0].Name),\n\t}\n}\n\n// SchemaRestoreFunc returns a function that restores the given schema to its desired state.\nfunc (d *Driver) SchemaRestoreFunc(desired *schema.Schema) migrate.RestoreFunc {\n\treturn func(ctx context.Context) error {\n\t\tcurrent, err := d.InspectSchema(ctx, desired.Name, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tchanges, err := d.SchemaDiff(current, desired)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn d.ApplyChanges(ctx, withCascade(changes))\n\t}\n}\n\n// RealmRestoreFunc returns a function that restores the given realm to its desired state.\nfunc (d *Driver) RealmRestoreFunc(desired *schema.Realm) migrate.RestoreFunc {\n\t// Default behavior for Postgres is to have a single \"public\" schema.\n\t// In that case, all other schemas are dropped, but this one is cleared\n\t// object by object. To keep process faster, we drop the schema and recreate it.\n\tif !d.crdb && len(desired.Schemas) == 1 && desired.Schemas[0].Name == \"public\" {\n\t\tif pb := desired.Schemas[0]; len(pb.Tables)+len(pb.Views)+len(pb.Funcs)+len(pb.Procs)+len(pb.Objects) == 0 {\n\t\t\treturn func(ctx context.Context) error {\n\t\t\t\tcurrent, err := d.InspectRealm(ctx, nil)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tchanges, err := d.RealmDiff(current, desired)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\t// If there is no diff, do nothing.\n\t\t\t\tif len(changes) == 0 {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t// Else, prefer to drop the public schema and apply\n\t\t\t\t// database changes instead of executing changes one by one.\n\t\t\t\tif changes, err = d.RealmDiff(current, &schema.Realm{Attrs: desired.Attrs, Objects: desired.Objects}); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif err := d.ApplyChanges(ctx, withCascade(changes)); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\t// Recreate the public schema.\n\t\t\t\treturn d.ApplyChanges(ctx, []schema.Change{\n\t\t\t\t\t&schema.AddSchema{S: pb, Extra: []schema.Clause{&schema.IfExists{}}},\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\treturn func(ctx context.Context) (err error) {\n\t\tcurrent, err := d.InspectRealm(ctx, nil)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tchanges, err := d.RealmDiff(current, desired)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn d.ApplyChanges(ctx, withCascade(changes))\n\t}\n}\n\nfunc withCascade(changes schema.Changes) schema.Changes {\n\tfor _, c := range changes {\n\t\tswitch c := c.(type) {\n\t\tcase *schema.DropTable:\n\t\t\tc.Extra = append(c.Extra, &schema.IfExists{}, &Cascade{})\n\t\tcase *schema.DropView:\n\t\t\tc.Extra = append(c.Extra, &schema.IfExists{}, &Cascade{})\n\t\tcase *schema.DropProc:\n\t\t\tc.Extra = append(c.Extra, &schema.IfExists{}, &Cascade{})\n\t\tcase *schema.DropFunc:\n\t\t\tc.Extra = append(c.Extra, &schema.IfExists{}, &Cascade{})\n\t\tcase *schema.DropObject:\n\t\t\tc.Extra = append(c.Extra, &schema.IfExists{}, &Cascade{})\n\t\t}\n\t}\n\treturn changes\n}\n\n// CheckClean implements migrate.CleanChecker.\nfunc (d *Driver) CheckClean(ctx context.Context, revT *migrate.TableIdent) error {\n\tif revT == nil { // accept nil values\n\t\trevT = &migrate.TableIdent{}\n\t}\n\tif d.schema != \"\" {\n\t\tswitch s, err := d.InspectSchema(ctx, d.schema, nil); {\n\t\tcase err != nil:\n\t\t\treturn err\n\t\tcase len(s.Tables) == 0, (revT.Schema == \"\" || s.Name == revT.Schema) && len(s.Tables) == 1 && s.Tables[0].Name == revT.Name:\n\t\t\treturn nil\n\t\tdefault:\n\t\t\treturn &migrate.NotCleanError{State: schema.NewRealm(s), Reason: fmt.Sprintf(\"found table %q in schema %q\", s.Tables[0].Name, s.Name)}\n\t\t}\n\t}\n\tr, err := d.InspectRealm(ctx, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, s := range r.Schemas {\n\t\tswitch {\n\t\tcase len(s.Tables) == 0 && s.Name == \"public\":\n\t\tcase len(s.Tables) == 0 || s.Name != revT.Schema:\n\t\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found schema %q\", s.Name)}\n\t\tcase len(s.Tables) > 1:\n\t\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found %d tables in schema %q\", len(s.Tables), s.Name)}\n\t\tcase len(s.Tables) == 1 && s.Tables[0].Name != revT.Name:\n\t\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found table %q in schema %q\", s.Tables[0].Name, s.Name)}\n\t\t}\n\t}\n\treturn nil\n}\n\n// Version returns the version of the connected database.\nfunc (d *Driver) Version() string {\n\treturn strconv.Itoa(d.conn.version)\n}\n\n// FormatType converts schema type to its column form in the database.\nfunc (*Driver) FormatType(t schema.Type) (string, error) {\n\treturn FormatType(t)\n}\n\n// ParseType returns the schema.Type value represented by the given string.\nfunc (*Driver) ParseType(s string) (schema.Type, error) {\n\treturn ParseType(s)\n}\n\n// StmtBuilder is a helper method used to build statements with PostgreSQL formatting.\nfunc (*Driver) StmtBuilder(opts migrate.PlanOptions) *sqlx.Builder {\n\treturn &sqlx.Builder{\n\t\tQuoteOpening: '\"',\n\t\tQuoteClosing: '\"',\n\t\tSchema:       opts.SchemaQualifier,\n\t\tIndent:       opts.Indent,\n\t}\n}\n\n// ScanStmts implements migrate.StmtScanner.\nfunc (*Driver) ScanStmts(input string) ([]*migrate.Stmt, error) {\n\treturn (&migrate.Scanner{\n\t\tScannerOptions: migrate.ScannerOptions{\n\t\t\tMatchBegin:       true,\n\t\t\tMatchBeginAtomic: true,\n\t\t\tMatchDollarQuote: true,\n\t\t\tEscapedStringExt: true,\n\t\t},\n\t}).Scan(input)\n}\n\n// Use pg_try_advisory_lock to avoid deadlocks between multiple executions of Atlas (commonly tests).\n// The common case is as follows: a process (P1) of Atlas takes a lock, and another process (P2) of\n// Atlas waits for the lock. Now if P1 execute \"CREATE INDEX CONCURRENTLY\" (either in apply or diff),\n// the command waits all active transactions that can potentially changed the index to be finished.\n// P2 can be executed in a transaction block (opened explicitly by Atlas), or a single statement tx\n// also known as \"autocommit mode\". Read more: https://www.postgresql.org/docs/current/sql-begin.html.\nfunc acquire(ctx context.Context, conn schema.ExecQuerier, id uint32, timeout time.Duration) error {\n\tvar (\n\t\tinter = 25\n\t\tstart = time.Now()\n\t)\n\tfor {\n\t\trows, err := conn.QueryContext(ctx, \"SELECT pg_try_advisory_lock($1)\", id)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tswitch acquired, err := sqlx.ScanNullBool(rows); {\n\t\tcase err != nil:\n\t\t\treturn err\n\t\tcase acquired.Bool:\n\t\t\treturn nil\n\t\tcase time.Since(start) > timeout:\n\t\t\treturn schema.ErrLocked\n\t\tdefault:\n\t\t\tif err := rows.Close(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// 25ms~50ms, 50ms~100ms, ..., 800ms~1.6s, 1s~2s.\n\t\t\td := min(time.Duration(inter)*time.Millisecond, time.Second)\n\t\t\ttime.Sleep(d + time.Duration(rand.Intn(int(d))))\n\t\t\tinter += inter\n\t\t}\n\t}\n}\n\n// supportsIndexInclude reports if the server supports the INCLUDE clause.\nfunc (c *conn) supportsIndexInclude() bool {\n\treturn c.version >= 11_00_00\n}\n\n// supportsIndexNullsDistinct reports if the server supports the NULLS [NOT] DISTINCT clause.\nfunc (c *conn) supportsIndexNullsDistinct() bool {\n\treturn c.version >= 15_00_00\n}\n\ntype parser struct{}\n\n// ParseURL implements the sqlclient.URLParser interface.\nfunc (parser) ParseURL(u *url.URL) *sqlclient.URL {\n\treturn &sqlclient.URL{URL: u, DSN: u.String(), Schema: u.Query().Get(\"search_path\")}\n}\n\n// ChangeSchema implements the sqlclient.SchemaChanger interface.\nfunc (parser) ChangeSchema(u *url.URL, s string) *url.URL {\n\tnu := *u\n\tq := nu.Query()\n\tq.Set(\"search_path\", s)\n\tnu.RawQuery = q.Encode()\n\treturn &nu\n}\n\n// Standard column types (and their aliases) as defined in\n// PostgreSQL codebase/website.\nconst (\n\tTypeBit     = \"bit\"\n\tTypeBitVar  = \"bit varying\"\n\tTypeBoolean = \"boolean\"\n\tTypeBool    = \"bool\" // boolean.\n\tTypeBytea   = \"bytea\"\n\n\tTypeCharacter = \"character\"\n\tTypeChar      = \"char\" // character\n\tTypeCharVar   = \"character varying\"\n\tTypeVarChar   = \"varchar\" // character varying\n\tTypeText      = \"text\"\n\tTypeBPChar    = \"bpchar\" // blank-padded character.\n\ttypeName      = \"name\"   // internal type for object names\n\n\tTypeSmallInt = \"smallint\"\n\tTypeInteger  = \"integer\"\n\tTypeBigInt   = \"bigint\"\n\tTypeInt      = \"int\"  // integer.\n\tTypeInt2     = \"int2\" // smallint.\n\tTypeInt4     = \"int4\" // integer.\n\tTypeInt8     = \"int8\" // bigint.\n\n\tTypeXID  = \"xid\"  // transaction identifier.\n\tTypeXID8 = \"xid8\" // 64-bit transaction identifier.\n\n\tTypeCIDR     = \"cidr\"\n\tTypeInet     = \"inet\"\n\tTypeMACAddr  = \"macaddr\"\n\tTypeMACAddr8 = \"macaddr8\"\n\n\tTypeCircle  = \"circle\"\n\tTypeLine    = \"line\"\n\tTypeLseg    = \"lseg\"\n\tTypeBox     = \"box\"\n\tTypePath    = \"path\"\n\tTypePolygon = \"polygon\"\n\tTypePoint   = \"point\"\n\n\tTypeDate          = \"date\"\n\tTypeTime          = \"time\"   // time without time zone\n\tTypeTimeTZ        = \"timetz\" // time with time zone\n\tTypeTimeWTZ       = \"time with time zone\"\n\tTypeTimeWOTZ      = \"time without time zone\"\n\tTypeTimestamp     = \"timestamp\" // timestamp without time zone\n\tTypeTimestampTZ   = \"timestamptz\"\n\tTypeTimestampWTZ  = \"timestamp with time zone\"\n\tTypeTimestampWOTZ = \"timestamp without time zone\"\n\n\tTypeDouble = \"double precision\"\n\tTypeReal   = \"real\"\n\tTypeFloat8 = \"float8\" // double precision\n\tTypeFloat4 = \"float4\" // real\n\tTypeFloat  = \"float\"  // float(p).\n\n\tTypeNumeric = \"numeric\"\n\tTypeDecimal = \"decimal\" // numeric\n\n\tTypeSmallSerial = \"smallserial\" // smallint with auto_increment.\n\tTypeSerial      = \"serial\"      // integer with auto_increment.\n\tTypeBigSerial   = \"bigserial\"   // bigint with auto_increment.\n\tTypeSerial2     = \"serial2\"     // smallserial\n\tTypeSerial4     = \"serial4\"     // serial\n\tTypeSerial8     = \"serial8\"     // bigserial\n\n\tTypeArray       = \"array\"\n\tTypeXML         = \"xml\"\n\tTypeJSON        = \"json\"\n\tTypeJSONB       = \"jsonb\"\n\tTypeUUID        = \"uuid\"\n\tTypeMoney       = \"money\"\n\tTypeInterval    = \"interval\"\n\tTypeTSQuery     = \"tsquery\"\n\tTypeTSVector    = \"tsvector\"\n\tTypeUserDefined = \"user-defined\"\n\n\tTypeInt4Range      = \"int4range\"\n\tTypeInt4MultiRange = \"int4multirange\"\n\tTypeInt8Range      = \"int8range\"\n\tTypeInt8MultiRange = \"int8multirange\"\n\tTypeNumRange       = \"numrange\"\n\tTypeNumMultiRange  = \"nummultirange\"\n\tTypeTSRange        = \"tsrange\"\n\tTypeTSMultiRange   = \"tsmultirange\"\n\tTypeTSTZRange      = \"tstzrange\"\n\tTypeTSTZMultiRange = \"tstzmultirange\"\n\tTypeDateRange      = \"daterange\"\n\tTypeDateMultiRange = \"datemultirange\"\n\n\t// PostgreSQL internal object types and their aliases.\n\ttypeOID           = \"oid\"\n\ttypeRegClass      = \"regclass\"\n\ttypeRegCollation  = \"regcollation\"\n\ttypeRegConfig     = \"regconfig\"\n\ttypeRegDictionary = \"regdictionary\"\n\ttypeRegNamespace  = \"regnamespace\"\n\ttypeRegOper       = \"regoper\"\n\ttypeRegOperator   = \"regoperator\"\n\ttypeRegProc       = \"regproc\"\n\ttypeRegProcedure  = \"regprocedure\"\n\ttypeRegRole       = \"regrole\"\n\ttypeRegType       = \"regtype\"\n\n\t// PostgreSQL of supported pseudo-types.\n\ttypeAny          = \"any\"\n\ttypeAnyElement   = \"anyelement\"\n\ttypeAnyArray     = \"anyarray\"\n\ttypeAnyNonArray  = \"anynonarray\"\n\ttypeAnyEnum      = \"anyenum\"\n\ttypeInternal     = \"internal\"\n\ttypeRecord       = \"record\"\n\ttypeTrigger      = \"trigger\"\n\ttypeEventTrigger = \"event_trigger\"\n\ttypeVoid         = \"void\"\n\ttypeUnknown      = \"unknown\"\n)\n\n// List of supported index types.\nconst (\n\tIndexTypeBTree       = \"BTREE\"\n\tIndexTypeBRIN        = \"BRIN\"\n\tIndexTypeHash        = \"HASH\"\n\tIndexTypeGIN         = \"GIN\"\n\tIndexTypeGiST        = \"GIST\"\n\tIndexTypeSPGiST      = \"SPGIST\"\n\tdefaultPagesPerRange = 128\n\tdefaultListLimit     = 4 * 1024\n\tdefaultBtreeFill     = 90\n)\n\nconst (\n\tstorageParamFillFactor = \"fillfactor\"\n\tstorageParamDedup      = \"deduplicate_items\"\n\tstorageParamBuffering  = \"buffering\"\n\tstorageParamFastUpdate = \"fastupdate\"\n\tstorageParamListLimit  = \"gin_pending_list_limit\"\n\tstorageParamPagesRange = \"pages_per_range\"\n\tstorageParamAutoSum    = \"autosummarize\"\n)\n\nconst (\n\tbufferingOff    = \"OFF\"\n\tbufferingOn     = \"ON\"\n\tbufferingAuto   = \"AUTO\"\n\tstorageParamOn  = \"ON\"\n\tstorageParamOff = \"OFF\"\n)\n\n// List of \"GENERATED\" types.\nconst (\n\tGeneratedTypeAlways    = \"ALWAYS\"\n\tGeneratedTypeByDefault = \"BY_DEFAULT\" // BY DEFAULT.\n)\n\n// List of PARTITION KEY types.\nconst (\n\tPartitionTypeRange = \"RANGE\"\n\tPartitionTypeList  = \"LIST\"\n\tPartitionTypeHash  = \"HASH\"\n)\n\nvar (\n\tspecOptions []schemahcl.Option\n\tspecFuncs   = &specutil.SchemaFuncs{\n\t\tTable: tableSpec,\n\t\tView:  viewSpec,\n\t}\n\tscanFuncs = &specutil.ScanFuncs{\n\t\tTable: convertTable,\n\t\tView:  convertView,\n\t}\n)\n\nfunc tableAttrsSpec(*schema.Table, *sqlspec.Table) {\n\t// unimplemented.\n}\n\nfunc convertTableAttrs(*sqlspec.Table, *schema.Table) error {\n\treturn nil // unimplemented.\n}\n\n// tableAttrDiff allows extending table attributes diffing with build-specific logic.\nfunc (*diff) tableAttrDiff(_, _ *schema.Table) ([]schema.Change, error) {\n\treturn nil, nil // unimplemented.\n}\n\n// addTableAttrs allows extending table attributes creation with build-specific logic.\nfunc (*state) addTableAttrs(_ *schema.AddTable) {\n\t// unimplemented.\n}\n\n// alterTableAttr allows extending table attributes alteration with build-specific logic.\nfunc (s *state) alterTableAttr(*sqlx.Builder, *schema.ModifyAttr) {\n\t// unimplemented.\n}\n\nfunc realmObjectsSpec(*doc, *schema.Realm) error {\n\treturn nil // unimplemented.\n}\n\nfunc triggersSpec([]*schema.Trigger, *doc) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*inspect) inspectViews(context.Context, *schema.Realm, *schema.InspectOptions) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*inspect) inspectFuncs(context.Context, *schema.Realm, *schema.InspectOptions) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*inspect) inspectTypes(context.Context, *schema.Realm, *schema.InspectOptions) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*inspect) inspectObjects(context.Context, *schema.Realm, *schema.InspectOptions) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*inspect) inspectTriggers(context.Context, *schema.Realm, *schema.InspectOptions) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*inspect) inspectDeps(context.Context, *schema.Realm, *schema.InspectOptions) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*inspect) inspectRealmObjects(context.Context, *schema.Realm, *schema.InspectOptions) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) addView(*schema.AddView) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) dropView(*schema.DropView) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) modifyView(*schema.ModifyView) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) renameView(*schema.RenameView) {\n\t// unimplemented.\n}\n\nfunc (s *state) addFunc(*schema.AddFunc) error {\n\treturn nil // unimplemented.\n}\n\nfunc (s *state) dropFunc(*schema.DropFunc) error {\n\treturn nil // unimplemented.\n}\n\nfunc (s *state) modifyFunc(*schema.ModifyFunc) error {\n\treturn nil // unimplemented.\n}\n\nfunc (s *state) renameFunc(*schema.RenameFunc) error {\n\treturn nil // unimplemented.\n}\n\nfunc (s *state) addProc(*schema.AddProc) error {\n\treturn nil // unimplemented.\n}\n\nfunc (s *state) dropProc(*schema.DropProc) error {\n\treturn nil // unimplemented.\n}\n\nfunc (s *state) modifyProc(*schema.ModifyProc) error {\n\treturn nil // unimplemented.\n}\n\nfunc (s *state) renameProc(*schema.RenameProc) error {\n\treturn nil // unimplemented.\n}\n\nfunc (s *state) addObject(add *schema.AddObject) error {\n\tswitch o := add.O.(type) {\n\tcase *schema.EnumType:\n\t\tcreate, drop := s.createDropEnum(o)\n\t\ts.append(&migrate.Change{\n\t\t\tSource:  add,\n\t\t\tCmd:     create,\n\t\t\tReverse: drop,\n\t\t\tComment: fmt.Sprintf(\"create enum type %q\", o.T),\n\t\t})\n\tdefault:\n\t\t// unsupported object type.\n\t}\n\treturn nil\n}\n\nfunc (s *state) dropObject(drop *schema.DropObject) error {\n\tswitch o := drop.O.(type) {\n\tcase *schema.EnumType:\n\t\tcreate, dropE := s.createDropEnum(o)\n\t\ts.append(&migrate.Change{\n\t\t\tSource:  drop,\n\t\t\tCmd:     dropE,\n\t\t\tReverse: create,\n\t\t\tComment: fmt.Sprintf(\"drop enum type %q\", o.T),\n\t\t})\n\tdefault:\n\t\t// unsupported object type.\n\t}\n\treturn nil\n}\n\nfunc (s *state) modifyObject(modify *schema.ModifyObject) error {\n\tif _, ok := modify.From.(*schema.EnumType); ok {\n\t\treturn s.alterEnum(modify)\n\t}\n\treturn nil // unimplemented.\n}\n\nfunc (*state) addTrigger(*schema.AddTrigger) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) dropTrigger(*schema.DropTrigger) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) renameTrigger(*schema.RenameTrigger) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) modifyTrigger(*schema.ModifyTrigger) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*diff) ViewAttrChanges(_, _ *schema.View) []schema.Change {\n\treturn nil // unimplemented.\n}\n\n// RealmObjectDiff returns a changeset for migrating realm (database) objects\n// from one state to the other. For example, adding extensions or users.\nfunc (*diff) RealmObjectDiff(_, _ *schema.Realm) ([]schema.Change, error) {\n\treturn nil, nil // unimplemented.\n}\n\n// SchemaObjectDiff returns a changeset for migrating schema objects from\n// one state to the other.\nfunc (*diff) SchemaObjectDiff(from, to *schema.Schema, _ *schema.DiffOptions) ([]schema.Change, error) {\n\tvar changes []schema.Change\n\t// Drop or modify enums.\n\tfor _, o1 := range from.Objects {\n\t\te1, ok := o1.(*schema.EnumType)\n\t\tif !ok {\n\t\t\tcontinue // Unsupported object type.\n\t\t}\n\t\to2, ok := to.Object(func(o schema.Object) bool {\n\t\t\te2, ok := o.(*schema.EnumType)\n\t\t\treturn ok && e1.T == e2.T\n\t\t})\n\t\tif !ok {\n\t\t\tchanges = append(changes, &schema.DropObject{O: o1})\n\t\t\tcontinue\n\t\t}\n\t\tif e2 := o2.(*schema.EnumType); !sqlx.ValuesEqual(e1.Values, e2.Values) {\n\t\t\tchanges = append(changes, &schema.ModifyObject{From: e1, To: e2})\n\t\t}\n\t}\n\t// Add new enums.\n\tfor _, o1 := range to.Objects {\n\t\te1, ok := o1.(*schema.EnumType)\n\t\tif !ok {\n\t\t\tcontinue // Unsupported object type.\n\t\t}\n\t\tif _, ok := from.Object(func(o schema.Object) bool {\n\t\t\te2, ok := o.(*schema.EnumType)\n\t\t\treturn ok && e1.T == e2.T\n\t\t}); !ok {\n\t\t\tchanges = append(changes, &schema.AddObject{O: e1})\n\t\t}\n\t}\n\treturn changes, nil\n}\n\nfunc verifyChanges(context.Context, []schema.Change) error {\n\treturn nil // unimplemented.\n}\n\nfunc convertDomains(_ []*sqlspec.Table, domains []*domain, _ *schema.Realm) error {\n\tif len(domains) > 0 {\n\t\treturn fmt.Errorf(\"postgres: domains are not supported by this version. Use: https://atlasgo.io/getting-started\")\n\t}\n\treturn nil\n}\n\nfunc convertAggregate(d *doc, _ *schema.Realm) error {\n\tif len(d.Aggregates) > 0 {\n\t\treturn fmt.Errorf(\"postgres: aggregates are not supported by this version. Use: https://atlasgo.io/getting-started\")\n\t}\n\treturn nil\n}\n\nfunc convertSequences(_ []*sqlspec.Table, seqs []*sqlspec.Sequence, _ *schema.Realm) error {\n\tif len(seqs) > 0 {\n\t\treturn fmt.Errorf(\"postgres: sequences are not supported by this version. Use: https://atlasgo.io/getting-started\")\n\t}\n\treturn nil\n}\n\nfunc convertPolicies(_ []*sqlspec.Table, ps []*policy, _ *schema.Realm) error {\n\tif len(ps) > 0 {\n\t\treturn fmt.Errorf(\"postgres: policies are not supported by this version. Use: https://atlasgo.io/getting-started\")\n\t}\n\treturn nil\n}\n\nfunc convertExtensions(exs []*extension, _ *schema.Realm) error {\n\tif len(exs) > 0 {\n\t\treturn fmt.Errorf(\"postgres: extensions are not supported by this version. Use: https://atlasgo.io/getting-started\")\n\t}\n\treturn nil\n}\n\nfunc convertEventTriggers(evs []*eventTrigger, _ *schema.Realm) error {\n\tif len(evs) > 0 {\n\t\treturn fmt.Errorf(\"postgres: event triggers are not supported by this version. Use: https://atlasgo.io/getting-started\")\n\t}\n\treturn nil\n}\n\nfunc normalizeRealm(*schema.Realm) error {\n\treturn nil\n}\n\nfunc schemasObjectSpec(*doc, ...*schema.Schema) error {\n\treturn nil // unimplemented.\n}\n\n// objectSpec converts from a concrete schema objects into specs.\nfunc objectSpec(d *doc, spec *specutil.SchemaSpec, s *schema.Schema) error {\n\tfor _, o := range s.Objects {\n\t\tif e, ok := o.(*schema.EnumType); ok {\n\t\t\td.Enums = append(d.Enums, &enum{\n\t\t\t\tName:   e.T,\n\t\t\t\tValues: e.Values,\n\t\t\t\tSchema: specutil.SchemaRef(spec.Schema.Name),\n\t\t\t})\n\t\t}\n\t}\n\treturn nil\n}\n\n// convertEnums converts possibly referenced column types (like enums) to\n// an actual schema.Type and sets it on the correct schema.Column.\nfunc convertTypes(d *doc, r *schema.Realm) error {\n\tif len(d.Enums) == 0 {\n\t\treturn nil\n\t}\n\tbyName := make(map[string]*schema.EnumType)\n\tfor _, e := range d.Enums {\n\t\tif byName[e.Name] != nil {\n\t\t\treturn fmt.Errorf(\"duplicate enum %q\", e.Name)\n\t\t}\n\t\tns, err := specutil.SchemaName(e.Schema)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"extract schema name from enum reference: %w\", err)\n\t\t}\n\t\tes, ok := r.Schema(ns)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"schema %q defined on enum %q was not found in realm\", ns, e.Name)\n\t\t}\n\t\te1 := &schema.EnumType{T: e.Name, Schema: es, Values: e.Values}\n\t\tes.AddObjects(e1)\n\t\tbyName[e.Name] = e1\n\t}\n\tfor _, t := range d.Tables {\n\t\tfor _, c := range t.Columns {\n\t\t\tvar enum *schema.EnumType\n\t\t\tswitch {\n\t\t\tcase c.Type.IsRefTo(\"enum\"):\n\t\t\t\tn, err := enumName(c.Type)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\te, ok := byName[n]\n\t\t\t\tif !ok {\n\t\t\t\t\treturn fmt.Errorf(\"enum %q was not found in realm\", n)\n\t\t\t\t}\n\t\t\t\tenum = e\n\t\t\tdefault:\n\t\t\t\tif n, ok := arrayType(c.Type.T); ok {\n\t\t\t\t\tenum = byName[n]\n\t\t\t\t}\n\t\t\t}\n\t\t\tif enum == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tschemaT, err := specutil.SchemaName(t.Schema)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"extract schema name from table reference: %w\", err)\n\t\t\t}\n\t\t\tts, ok := r.Schema(schemaT)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"schema %q not found in realm for table %q\", schemaT, t.Name)\n\t\t\t}\n\t\t\ttt, ok := ts.Table(t.Name)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"table %q not found in schema %q\", t.Name, ts.Name)\n\t\t\t}\n\t\t\tcc, ok := tt.Column(c.Name)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"column %q not found in table %q\", c.Name, t.Name)\n\t\t\t}\n\t\t\tswitch t := cc.Type.Type.(type) {\n\t\t\tcase *ArrayType:\n\t\t\t\tt.Type = enum\n\t\t\tdefault:\n\t\t\t\tcc.Type.Type = enum\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc indexToUnique(*schema.ModifyIndex) (*AddUniqueConstraint, bool) {\n\treturn nil, false // unimplemented.\n}\n\nfunc uniqueConstChanged(_, _ []schema.Attr) bool {\n\t// Unsupported change in package mode (ariga.io/sql/postgres)\n\t// to keep BC with old versions.\n\treturn false\n}\n\nfunc excludeConstChanged(_, _ []schema.Attr) bool {\n\t// Unsupported change in package mode (ariga.io/sql/postgres)\n\t// to keep BC with old versions.\n\treturn false\n}\n\nfunc convertExclude(schemahcl.Resource, *schema.Table) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) sortChanges(changes []schema.Change) []schema.Change {\n\treturn sqlx.SortChanges(changes, nil)\n}\n\nfunc (*state) detachCycles(changes []schema.Change) ([]schema.Change, error) {\n\treturn sqlx.DetachCycles(changes)\n}\n\nfunc excludeSpec(*sqlspec.Table, *sqlspec.Index, *schema.Index, *Constraint) error {\n\treturn nil // unimplemented.\n}\n\nconst (\n\t// Query to list tables information.\n\t// Note, 'attrs' are not supported in this version.\n\ttablesQuery = `\nSELECT\n\tt3.oid,\n\tt1.table_schema,\n\tt1.table_name,\n\tpg_catalog.obj_description(t3.oid, 'pg_class') AS comment,\n\tt4.partattrs AS partition_attrs,\n\tt4.partstrat AS partition_strategy,\n\tpg_get_expr(t4.partexprs, t4.partrelid) AS partition_exprs,\n\t'{}' AS attrs\nFROM\n\tINFORMATION_SCHEMA.TABLES AS t1\n\tJOIN pg_catalog.pg_namespace AS t2 ON t2.nspname = t1.table_schema\n\tJOIN pg_catalog.pg_class AS t3 ON t3.relnamespace = t2.oid AND t3.relname = t1.table_name\n\tLEFT JOIN pg_catalog.pg_partitioned_table AS t4 ON t4.partrelid = t3.oid\n\tLEFT JOIN pg_depend AS t5 ON t5.classid = 'pg_catalog.pg_class'::regclass::oid AND t5.objid = t3.oid AND t5.deptype = 'e'\nWHERE\n\tt1.table_type = 'BASE TABLE'\n\tAND NOT COALESCE(t3.relispartition, false)\n\tAND t1.table_schema IN (%s)\n\tAND t5.objid IS NULL\nORDER BY\n\tt1.table_schema, t1.table_name\n`\n\t// Query to list tables by their names.\n\t// Note, 'attrs' are not supported in this version.\n\ttablesQueryArgs = `\nSELECT\n\tt3.oid,\n\tt1.table_schema,\n\tt1.table_name,\n\tpg_catalog.obj_description(t3.oid, 'pg_class') AS comment,\n\tt4.partattrs AS partition_attrs,\n\tt4.partstrat AS partition_strategy,\n\tpg_get_expr(t4.partexprs, t4.partrelid) AS partition_exprs,\n\t'{}' AS attrs\nFROM\n\tINFORMATION_SCHEMA.TABLES AS t1\n\tJOIN pg_catalog.pg_namespace AS t2 ON t2.nspname = t1.table_schema\n\tJOIN pg_catalog.pg_class AS t3 ON t3.relnamespace = t2.oid AND t3.relname = t1.table_name\n\tLEFT JOIN pg_catalog.pg_partitioned_table AS t4 ON t4.partrelid = t3.oid\n\tLEFT JOIN pg_depend AS t5 ON t5.classid = 'pg_catalog.pg_class'::regclass::oid AND t5.objid = t3.oid AND t5.deptype = 'e'\nWHERE\n\tt1.table_type = 'BASE TABLE'\n\tAND NOT COALESCE(t3.relispartition, false)\n\tAND t1.table_schema IN (%s)\n\tAND t1.table_name IN (%s)\n\tAND t5.objid IS NULL\nORDER BY\n\tt1.table_schema, t1.table_name\n`\n)\n"
  },
  {
    "path": "sql/postgres/driver_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/internal/sqltest\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDriver_LockAcquired(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tname, hash := \"name\", 797654004\n\n\tt.Run(\"NoTimeout\", func(t *testing.T) {\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT pg_try_advisory_lock($1)\")).\n\t\t\tWithArgs(hash).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"pg_advisory_lock\"}).AddRow(1)).\n\t\t\tRowsWillBeClosed()\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT pg_advisory_unlock($1)\")).\n\t\t\tWithArgs(hash).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"pg_advisory_unlock\"}).AddRow(1)).\n\t\t\tRowsWillBeClosed()\n\n\t\td := &Driver{conn: &conn{ExecQuerier: db}}\n\t\tunlock, err := d.Lock(context.Background(), name, 0)\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, unlock())\n\t\trequire.NoError(t, m.ExpectationsWereMet())\n\t})\n\n\tt.Run(\"WithTimeout\", func(t *testing.T) {\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT pg_try_advisory_lock($1)\")).\n\t\t\tWithArgs(hash).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"pg_advisory_lock\"}).AddRow(0)).\n\t\t\tRowsWillBeClosed()\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT pg_try_advisory_lock($1)\")).\n\t\t\tWithArgs(hash).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"pg_advisory_lock\"}).AddRow(1)).\n\t\t\tRowsWillBeClosed()\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT pg_advisory_unlock($1)\")).\n\t\t\tWithArgs(hash).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"pg_advisory_unlock\"}).AddRow(1)).\n\t\t\tRowsWillBeClosed()\n\n\t\td := &Driver{conn: &conn{ExecQuerier: db}}\n\t\tunlock, err := d.Lock(context.Background(), name, time.Second)\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, unlock())\n\t\trequire.NoError(t, m.ExpectationsWereMet())\n\t})\n}\n\nfunc TestDriver_LockError(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\td := &Driver{conn: &conn{ExecQuerier: db}}\n\tname, hash := \"migrate\", 979249972\n\n\tt.Run(\"Internal\", func(t *testing.T) {\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT pg_try_advisory_lock($1)\")).\n\t\t\tWithArgs(hash).\n\t\t\tWillReturnError(io.EOF).\n\t\t\tRowsWillBeClosed()\n\t\tunlock, err := d.Lock(context.Background(), name, time.Minute)\n\t\trequire.Equal(t, io.EOF, err)\n\t\trequire.Nil(t, unlock)\n\t})\n}\n\nfunc TestDriver_UnlockError(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\td := &Driver{conn: &conn{ExecQuerier: db}}\n\tname, hash := \"up\", 1551306158\n\tacquired := func() {\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT pg_try_advisory_lock($1)\")).\n\t\t\tWithArgs(hash).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"pg_try_advisory_lock\"}).AddRow(1)).\n\t\t\tRowsWillBeClosed()\n\t}\n\n\tt.Run(\"NotHeld\", func(t *testing.T) {\n\t\tacquired()\n\t\tunlock, err := d.Lock(context.Background(), name, 0)\n\t\trequire.NoError(t, err)\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT pg_advisory_unlock($1)\")).\n\t\t\tWithArgs(hash).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"pg_advisory_unlock\"}).AddRow(0)).\n\t\t\tRowsWillBeClosed()\n\t\trequire.Error(t, unlock())\n\t})\n\n\tt.Run(\"Internal\", func(t *testing.T) {\n\t\tacquired()\n\t\tunlock, err := d.Lock(context.Background(), name, 0)\n\t\trequire.NoError(t, err)\n\t\tm.ExpectQuery(sqltest.Escape(\"SELECT pg_advisory_unlock($1)\")).\n\t\t\tWithArgs(hash).\n\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"pg_advisory_unlock\"}).AddRow(nil)).\n\t\t\tRowsWillBeClosed()\n\t\trequire.Error(t, unlock())\n\t})\n}\n\nfunc TestDriver_CheckClean(t *testing.T) {\n\ts := schema.New(\"test\")\n\tdrv := &Driver{Inspector: &mockInspector{schema: s}, conn: &conn{schema: \"test\"}}\n\t// Empty schema.\n\terr := drv.CheckClean(context.Background(), nil)\n\trequire.NoError(t, err)\n\t// Revisions table found.\n\ts.AddTables(schema.NewTable(\"revisions\"))\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Name: \"revisions\", Schema: \"test\"})\n\trequire.NoError(t, err)\n\t// Multiple tables.\n\ts.Tables = []*schema.Table{schema.NewTable(\"a\"), schema.NewTable(\"revisions\")}\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Name: \"revisions\", Schema: \"test\"})\n\trequire.EqualError(t, err, `sql/migrate: connected database is not clean: found table \"a\" in schema \"test\"`)\n\n\tr := schema.NewRealm()\n\tdrv.schema = \"\"\n\tdrv.Inspector = &mockInspector{realm: r}\n\t// Empty realm.\n\terr = drv.CheckClean(context.Background(), nil)\n\trequire.NoError(t, err)\n\t// Revisions table found.\n\ts.Tables = []*schema.Table{schema.NewTable(\"revisions\").SetSchema(s)}\n\tr.AddSchemas(s)\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Name: \"revisions\", Schema: \"test\"})\n\trequire.NoError(t, err)\n\t// Unknown table.\n\ts.Tables[0].Name = \"unknown\"\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Schema: \"test\", Name: \"revisions\"})\n\trequire.EqualError(t, err, `sql/migrate: connected database is not clean: found table \"unknown\" in schema \"test\"`)\n\t// Multiple tables.\n\ts.Tables = []*schema.Table{schema.NewTable(\"a\"), schema.NewTable(\"revisions\")}\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Schema: \"test\", Name: \"revisions\"})\n\trequire.EqualError(t, err, `sql/migrate: connected database is not clean: found 2 tables in schema \"test\"`)\n\t// With auto created public schema.\n\ts.Tables = []*schema.Table{schema.NewTable(\"revisions\")}\n\tr.AddSchemas(schema.New(\"public\"))\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Schema: \"test\", Name: \"revisions\"})\n\trequire.NoError(t, err)\n}\n\nfunc TestDriver_Version(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmock{m}.version(\"130000\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\n\ttype vr interface{ Version() string }\n\trequire.Implements(t, (*vr)(nil), drv)\n\trequire.Equal(t, \"130000\", drv.(vr).Version())\n}\n\nfunc TestDriver_RealmRestoreFunc(t *testing.T) {\n\tvar (\n\t\tapply   = &mockPlanApplier{}\n\t\tinspect = &mockInspector{}\n\t\tdrv     = &Driver{\n\t\t\tInspector:   inspect,\n\t\t\tDiffer:      DefaultDiff,\n\t\t\tconn:        &conn{schema: \"test\"},\n\t\t\tPlanApplier: apply,\n\t\t}\n\t)\n\tf := drv.RealmRestoreFunc(schema.NewRealm().AddSchemas(schema.New(\"public\")))\n\n\t// No changes.\n\tinspect.realm = schema.NewRealm().AddSchemas(schema.New(\"public\"))\n\terr := f(context.Background())\n\trequire.NoError(t, err)\n\trequire.Empty(t, apply.applied)\n\n\t// Schema changes.\n\tinspect.realm = schema.NewRealm().AddSchemas(schema.New(\"public\").AddTables(schema.NewTable(\"t1\")))\n\terr = f(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, apply.applied, 2)\n\tdrop, ok := apply.applied[0].(*schema.DropSchema)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"public\", drop.S.Name)\n\tcreate, ok := apply.applied[1].(*schema.AddSchema)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"public\", create.S.Name)\n\n\t// Recreate the public schema.\n\tapply.applied = nil\n\tinspect.realm = schema.NewRealm().AddSchemas(schema.New(\"test\").AddTables(schema.NewTable(\"t1\")))\n\terr = f(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, apply.applied, 2)\n\tdrop, ok = apply.applied[0].(*schema.DropSchema)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"test\", drop.S.Name)\n\tcreate, ok = apply.applied[1].(*schema.AddSchema)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"public\", create.S.Name)\n\n\t// Non-public changes.\n\tapply.applied = nil\n\tf = drv.RealmRestoreFunc(schema.NewRealm().AddSchemas(schema.New(\"test\")))\n\tinspect.realm = schema.NewRealm().AddSchemas(schema.New(\"test\").AddTables(schema.NewTable(\"t1\")))\n\terr = f(context.Background())\n\trequire.NoError(t, err)\n\trequire.Len(t, apply.applied, 1)\n\tdropT, ok := apply.applied[0].(*schema.DropTable)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"t1\", dropT.T.Name)\n}\n\ntype mockInspector struct {\n\tschema.Inspector\n\trealm  *schema.Realm\n\tschema *schema.Schema\n}\n\nfunc (m *mockInspector) InspectSchema(context.Context, string, *schema.InspectOptions) (*schema.Schema, error) {\n\tif m.schema == nil {\n\t\treturn nil, &schema.NotExistError{}\n\t}\n\treturn m.schema, nil\n}\n\nfunc (m *mockInspector) InspectRealm(context.Context, *schema.InspectRealmOption) (*schema.Realm, error) {\n\treturn m.realm, nil\n}\n\ntype mockPlanApplier struct {\n\tplanned []schema.Change\n\tapplied []schema.Change\n}\n\nfunc (m *mockPlanApplier) PlanChanges(_ context.Context, _ string, planned []schema.Change, _ ...migrate.PlanOption) (*migrate.Plan, error) {\n\tm.planned = append(m.planned, planned...)\n\treturn nil, nil\n}\n\nfunc (m *mockPlanApplier) ApplyChanges(_ context.Context, applied []schema.Change, _ ...migrate.PlanOption) error {\n\tm.applied = append(m.applied, applied...)\n\treturn nil\n}\n"
  },
  {
    "path": "sql/postgres/inspect_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/specutil\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/postgres/internal/postgresop\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// A diff provides a PostgreSQL implementation for schema.Inspector.\ntype inspect struct{ *conn }\n\nvar _ schema.Inspector = (*inspect)(nil)\n\n// InspectRealm returns schema descriptions of all resources in the given realm.\nfunc (i *inspect) InspectRealm(ctx context.Context, opts *schema.InspectRealmOption) (_ *schema.Realm, rerr error) {\n\tundo, err := i.noSearchPath(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() { rerr = errors.Join(rerr, undo()) }()\n\tschemas, err := i.schemas(ctx, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif opts == nil {\n\t\topts = &schema.InspectRealmOption{}\n\t}\n\tvar (\n\t\tr    = schema.NewRealm(schemas...)\n\t\tmode = sqlx.ModeInspectRealm(opts)\n\t)\n\tif len(schemas) > 0 {\n\t\tif mode.Is(schema.InspectTypes) {\n\t\t\tif err := i.inspectEnums(ctx, r); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif err := i.inspectTypes(ctx, r, nil); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tif mode.Is(schema.InspectTables) {\n\t\t\tif err := i.inspectTables(ctx, r, nil); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tsqlx.LinkSchemaTables(schemas)\n\t\t}\n\t\tif mode.Is(schema.InspectViews) {\n\t\t\tif err := i.inspectViews(ctx, r, nil); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tif mode.Is(schema.InspectFuncs) {\n\t\t\tif err := i.inspectFuncs(ctx, r, nil); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tif mode.Is(schema.InspectObjects) {\n\t\t\tif err := i.inspectObjects(ctx, r, nil); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif err := i.inspectRealmObjects(ctx, r, nil); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tif mode.Is(schema.InspectTriggers) {\n\t\t\tif err := i.inspectTriggers(ctx, r, nil); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tif err := i.inspectDeps(ctx, r, nil); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn schema.ExcludeRealm(r, opts.Exclude)\n}\n\n// noSearchPath ensures the session search_path is clean when inspecting realms to ensures all\n// referenced objects in the public schema (or any other default search_path) are returned\n// qualified in the inspection.\nfunc (i *inspect) noSearchPath(ctx context.Context) (func() error, error) {\n\tif i.crdb {\n\t\t// Skip logic for CockroachDB.\n\t\treturn func() error { return nil }, nil\n\t}\n\trows, err := i.QueryContext(ctx, \"SELECT current_setting('search_path'), set_config('search_path', '', false)\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar prev sql.NullString\n\tif err := sqlx.ScanOne(rows, &prev, &sql.NullString{}); err != nil {\n\t\treturn nil, err\n\t}\n\treturn func() error {\n\t\tif sqlx.ValidString(prev) {\n\t\t\trows, err := i.QueryContext(ctx, \"SELECT set_config('search_path', $1, false)\", prev.String)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn rows.Close()\n\t\t}\n\t\treturn nil\n\t}, nil\n}\n\n// InspectSchema returns schema descriptions of the tables in the given schema.\n// If the schema name is empty, the result will be the attached schema.\nfunc (i *inspect) InspectSchema(ctx context.Context, name string, opts *schema.InspectOptions) (s *schema.Schema, err error) {\n\tif name == \"\" && i.schema != \"\" {\n\t\tname = i.schema // Otherwise, the \"current_schema()\" is used.\n\t}\n\tschemas, err := i.schemas(ctx, &schema.InspectRealmOption{Schemas: []string{name}})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch n := len(schemas); {\n\tcase n == 0:\n\t\t// Empty string indicates current connected schema.\n\t\tif name == \"\" {\n\t\t\treturn nil, &schema.NotExistError{Err: errors.New(\"postgres: current_schema() defined in search_path was not found\")}\n\t\t}\n\t\treturn nil, &schema.NotExistError{Err: fmt.Errorf(\"postgres: schema %q was not found\", name)}\n\tcase n > 1:\n\t\treturn nil, fmt.Errorf(\"postgres: %d schemas were found for %q\", n, name)\n\t}\n\tif opts == nil {\n\t\topts = &schema.InspectOptions{}\n\t}\n\tvar (\n\t\tr    = schema.NewRealm(schemas...)\n\t\tmode = sqlx.ModeInspectSchema(opts)\n\t)\n\tif mode.Is(schema.InspectTypes) {\n\t\tif err := i.inspectEnums(ctx, r); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := i.inspectTypes(ctx, r, opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif mode.Is(schema.InspectTables) {\n\t\tif err := i.inspectTables(ctx, r, opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsqlx.LinkSchemaTables(schemas)\n\t}\n\tif mode.Is(schema.InspectViews) {\n\t\tif err := i.inspectViews(ctx, r, opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif mode.Is(schema.InspectFuncs) {\n\t\tif err := i.inspectFuncs(ctx, r, opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif mode.Is(schema.InspectObjects) {\n\t\tif err := i.inspectObjects(ctx, r, opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif mode.Is(schema.InspectTriggers) {\n\t\tif err := i.inspectTriggers(ctx, r, nil); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif err := i.inspectDeps(ctx, r, opts); err != nil {\n\t\treturn nil, err\n\t}\n\treturn schema.ExcludeSchema(r.Schemas[0], opts.Exclude)\n}\n\nfunc (i *inspect) inspectTables(ctx context.Context, r *schema.Realm, opts *schema.InspectOptions) error {\n\tif err := i.tables(ctx, r, opts); err != nil {\n\t\treturn err\n\t}\n\tfor _, s := range r.Schemas {\n\t\tif len(s.Tables) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif err := i.columns(ctx, s); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := i.indexes(ctx, s); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := i.partitions(s); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := i.fks(ctx, s); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := i.checks(ctx, s); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// table returns the table from the database, or a NotExistError if the table was not found.\nfunc (i *inspect) tables(ctx context.Context, realm *schema.Realm, opts *schema.InspectOptions) error {\n\tvar (\n\t\targs  []any\n\t\tquery = fmt.Sprintf(tablesQuery, nArgs(0, len(realm.Schemas)))\n\t)\n\tfor _, s := range realm.Schemas {\n\t\targs = append(args, s.Name)\n\t}\n\tif opts != nil && len(opts.Tables) > 0 {\n\t\tfor _, t := range opts.Tables {\n\t\t\targs = append(args, t)\n\t\t}\n\t\tquery = fmt.Sprintf(tablesQueryArgs, nArgs(0, len(realm.Schemas)), nArgs(len(realm.Schemas), len(opts.Tables)))\n\t}\n\trows, err := i.QueryContext(ctx, query, args...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar (\n\t\t\toid                                                            sql.NullInt64\n\t\t\ttSchema, name, comment, partattrs, partstart, partexprs, extra sql.NullString\n\t\t)\n\t\tif err := rows.Scan(&oid, &tSchema, &name, &comment, &partattrs, &partstart, &partexprs, &extra); err != nil {\n\t\t\treturn fmt.Errorf(\"scan table information: %w\", err)\n\t\t}\n\t\tif !sqlx.ValidString(tSchema) || !sqlx.ValidString(name) {\n\t\t\treturn fmt.Errorf(\"invalid schema or table name: %q.%q\", tSchema.String, name.String)\n\t\t}\n\t\ts, ok := realm.Schema(tSchema.String)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"schema %q was not found in realm\", tSchema.String)\n\t\t}\n\t\tt := schema.NewTable(name.String)\n\t\ts.AddTables(t)\n\t\tif oid.Valid {\n\t\t\tt.AddAttrs(&OID{V: oid.Int64})\n\t\t}\n\t\tif sqlx.ValidString(comment) {\n\t\t\tt.SetComment(comment.String)\n\t\t}\n\t\tif sqlx.ValidString(partattrs) {\n\t\t\tt.AddAttrs(&Partition{\n\t\t\t\tstart: partstart.String,\n\t\t\t\tattrs: partattrs.String,\n\t\t\t\texprs: partexprs.String,\n\t\t\t})\n\t\t}\n\t}\n\treturn rows.Err()\n}\n\n// columns queries and appends the columns of the given table.\nfunc (i *inspect) columns(ctx context.Context, s *schema.Schema) error {\n\tquery := columnsQuery\n\tif i.crdb {\n\t\tquery = crdbColumnsQuery\n\t}\n\trows, err := i.querySchema(ctx, query, s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"postgres: querying schema %q columns: %w\", s.Name, err)\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tif err := i.addColumn(s, rows); err != nil {\n\t\t\treturn fmt.Errorf(\"postgres: %w\", err)\n\t\t}\n\t}\n\treturn rows.Err()\n}\n\n// addColumn scans the current row and adds a new column from it to the scope (table or view).\nfunc (i *inspect) addColumn(s *schema.Schema, rows *sql.Rows) (err error) {\n\tvar (\n\t\ttypid, typelem, maxlen, precision, timeprecision, scale, seqstart, seqinc, seqlast, attnum                                 sql.NullInt64\n\t\ttable, name, typ, fmtype, nullable, defaults, identity, genidentity, genexpr, charset, collate, comment, typtype, interval sql.NullString\n\t)\n\tif err = rows.Scan(\n\t\t&table, &name, &typ, &fmtype, &nullable, &defaults, &maxlen, &precision, &timeprecision, &scale, &interval, &charset,\n\t\t&collate, &identity, &seqstart, &seqinc, &seqlast, &genidentity, &genexpr, &comment, &typtype, &typelem, &typid, &attnum,\n\t); err != nil {\n\t\treturn err\n\t}\n\tt, ok := s.Table(table.String)\n\tif !ok {\n\t\treturn fmt.Errorf(\"table %q was not found in schema\", table.String)\n\t}\n\tc := &schema.Column{\n\t\tName: name.String,\n\t\tType: &schema.ColumnType{\n\t\t\tNull: nullable.String == \"YES\",\n\t\t\tRaw: func() string {\n\t\t\t\t// For domains, use the domain type instead of the base type.\n\t\t\t\tif typtype.String == \"d\" {\n\t\t\t\t\treturn fmtype.String\n\t\t\t\t}\n\t\t\t\treturn typ.String\n\t\t\t}(),\n\t\t},\n\t}\n\tc.Type.Type, err = columnType(&columnDesc{\n\t\ttyp:           typ.String,\n\t\tfmtype:        fmtype.String,\n\t\tsize:          maxlen.Int64,\n\t\tscale:         scale.Int64,\n\t\ttyptype:       typtype.String,\n\t\ttypelem:       typelem.Int64,\n\t\ttypid:         typid.Int64,\n\t\tinterval:      interval.String,\n\t\tprecision:     precision.Int64,\n\t\ttimePrecision: &timeprecision.Int64,\n\t})\n\tswitch tt := c.Type.Type.(type) {\n\tcase *ArrayType:\n\t\tif u, ok := tt.Underlying().(*UserDefinedType); ok {\n\t\t\ttt.Type = i.underlyingType(s, u)\n\t\t}\n\tcase *UserDefinedType:\n\t\tut := i.underlyingType(s, tt)\n\t\tif ut != tt {\n\t\t\tc.Type.Raw = tt.T\n\t\t\tc.Type.Type = ut\n\t\t}\n\t}\n\tif defaults.Valid {\n\t\tcolumnDefault(c, defaults.String)\n\t}\n\tif identity.String == \"YES\" {\n\t\tc.Attrs = append(c.Attrs, &Identity{\n\t\t\tGeneration: genidentity.String,\n\t\t\tSequence: &Sequence{\n\t\t\t\tLast:      seqlast.Int64,\n\t\t\t\tStart:     seqstart.Int64,\n\t\t\t\tIncrement: seqinc.Int64,\n\t\t\t},\n\t\t})\n\t}\n\tif sqlx.ValidString(genexpr) {\n\t\tc.Attrs = append(c.Attrs, &schema.GeneratedExpr{\n\t\t\tExpr: genexpr.String,\n\t\t})\n\t}\n\tif sqlx.ValidString(comment) {\n\t\tc.SetComment(comment.String)\n\t}\n\tif sqlx.ValidString(charset) {\n\t\tc.SetCharset(charset.String)\n\t}\n\tif sqlx.ValidString(collate) {\n\t\tc.SetCollation(collate.String)\n\t}\n\tt.AddColumns(c)\n\treturn nil\n}\n\n// parseType is like ParseType, but aware of the Realm state.\nfunc (i *inspect) parseType(ns *schema.Schema, s string) (schema.Type, error) {\n\tt, err := ParseType(s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch tt := t.(type) {\n\tcase *ArrayType:\n\t\tif u, ok := tt.Underlying().(*UserDefinedType); ok {\n\t\t\ttt.Type = i.underlyingType(ns, u)\n\t\t}\n\tcase *UserDefinedType:\n\t\tt = i.underlyingType(ns, tt)\n\t}\n\treturn t, nil\n}\n\n// underlyingType returns the underlying type of the given user-defined\n// type by searching the realm.\nfunc (i *inspect) underlyingType(s *schema.Schema, u *UserDefinedType) schema.Type {\n\tvar (\n\t\tsr       []*schema.Schema\n\t\tns, name = parseFmtType(u.T)\n\t)\n\tswitch nsScope := i.schema != \"\"; {\n\t// If the scope is one schema, the namespace defined\n\t// on the type because it resides on a different schema.\n\tcase ns == \"\":\n\t\tif !nsScope && s.Realm != nil {\n\t\t\t// Search in the \"public\" schema first, because in the default\n\t\t\t// configuration unqualified types refer to the public schema.\n\t\t\tif s1, ok := s.Realm.Schema(\"public\"); ok {\n\t\t\t\tsr = append(sr, s1)\n\t\t\t}\n\t\t}\n\t\tsr = append(sr, s)\n\t// Allow searching in other schemas, only if\n\t// we are not in a schema scope.\n\tcase ns != \"\" && !nsScope && s.Realm != nil:\n\t\tif s1, ok := s.Realm.Schema(ns); ok {\n\t\t\tsr = []*schema.Schema{s1}\n\t\t}\n\t}\n\tfor _, s := range sr {\n\t\tfor _, o := range s.Objects {\n\t\t\tif e, ok := o.(*schema.EnumType); ok && e.T == name {\n\t\t\t\treturn e\n\t\t\t} else if d, ok := o.(*DomainType); ok && d.T == name {\n\t\t\t\treturn d\n\t\t\t} else if c, ok := o.(*CompositeType); ok && c.T == name {\n\t\t\t\treturn c\n\t\t\t}\n\t\t}\n\t}\n\t// No match.\n\treturn u\n}\n\n// enumValues fills enum columns with their values from the database.\nfunc (i *inspect) inspectEnums(ctx context.Context, r *schema.Realm) error {\n\tvar (\n\t\tids  = make(map[int64]*schema.EnumType)\n\t\targs = make([]any, 0, len(r.Schemas))\n\t)\n\tfor _, s := range r.Schemas {\n\t\targs = append(args, s.Name)\n\t}\n\tif len(args) == 0 {\n\t\treturn nil\n\t}\n\trows, err := i.QueryContext(ctx, fmt.Sprintf(enumsQuery, nArgs(0, len(args))), args...)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"postgres: querying enum values: %w\", err)\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tid       int64\n\t\t\tns, n, v string\n\t\t)\n\t\tif err := rows.Scan(&ns, &id, &n, &v); err != nil {\n\t\t\treturn fmt.Errorf(\"postgres: scanning enum label: %w\", err)\n\t\t}\n\t\te, ok := ids[id]\n\t\tif !ok {\n\t\t\te = &schema.EnumType{T: n}\n\t\t\tids[id] = e\n\t\t}\n\t\tif e.Schema == nil {\n\t\t\ts, ok := r.Schema(ns)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"postgres: schema %q for enum %q was not found in inspection\", ns, e.T)\n\t\t\t}\n\t\t\te.Schema = s\n\t\t\ts.Objects = append(s.Objects, e)\n\t\t}\n\t\te.Values = append(e.Values, v)\n\t}\n\treturn nil\n}\n\n// indexes queries and appends the indexes of the given table.\nfunc (i *inspect) indexes(ctx context.Context, s *schema.Schema) error {\n\tif i.crdb {\n\t\treturn i.crdbIndexes(ctx, s)\n\t}\n\trows, err := i.querySchema(ctx, i.indexesQuery(), s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"postgres: querying schema %q indexes: %w\", s.Name, err)\n\t}\n\tdefer rows.Close()\n\tif err := i.addIndexes(s, rows, queryScope{\n\t\thasT: func(tv string) bool {\n\t\t\t_, ok := s.Table(tv)\n\t\t\treturn ok\n\t\t},\n\t\tsetPK: func(tv string, idx *schema.Index) error {\n\t\t\tif t, ok := s.Table(tv); ok {\n\t\t\t\tt.SetPrimaryKey(idx)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"postgres: table %q for primary key was not found in schema\", tv)\n\t\t},\n\t\taddIndex: func(tv string, idx *schema.Index) error {\n\t\t\tif t, ok := s.Table(tv); ok {\n\t\t\t\tt.AddIndexes(idx)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"postgres: table %q for index was not found in schema\", tv)\n\t\t},\n\t\tcolumn: func(tv, name string) (*schema.Column, bool) {\n\t\t\tif t, ok := s.Table(tv); ok {\n\t\t\t\treturn t.Column(name)\n\t\t\t}\n\t\t\treturn nil, false\n\t\t},\n\t}); err != nil {\n\t\treturn err\n\t}\n\treturn rows.Err()\n}\n\nfunc (i *inspect) indexesQuery() (q string) {\n\tswitch {\n\tcase i.supportsIndexNullsDistinct():\n\t\tq = indexesAbove15\n\tcase i.supportsIndexInclude():\n\t\tq = indexesAbove11\n\tdefault:\n\t\tq = indexesBelow11\n\t}\n\treturn\n}\n\ntype queryScope struct {\n\thasT     func(tv string) bool\n\tsetPK    func(tv string, idx *schema.Index) error\n\taddIndex func(tv string, idx *schema.Index) error\n\tcolumn   func(tv, name string) (*schema.Column, bool)\n}\n\n// addIndexes scans the rows and adds the indexes to the table.\nfunc (i *inspect) addIndexes(s *schema.Schema, rows *sql.Rows, scope queryScope) error {\n\tnames := make(map[string]*schema.Index)\n\tfor rows.Next() {\n\t\tvar (\n\t\t\ttable, name, typ                                                                         string\n\t\t\tuniq, primary, included, nullsnotdistinct                                                bool\n\t\t\tdesc, nullsfirst, nullslast, opcdefault                                                  sql.NullBool\n\t\t\tcolumn, constraints, pred, expr, comment, options, opcname, opcschema, opcparams, exoper sql.NullString\n\t\t)\n\t\tif err := rows.Scan(\n\t\t\t&table, &name, &typ, &column, &included, &primary, &uniq, &exoper, &constraints, &pred, &expr, &desc,\n\t\t\t&nullsfirst, &nullslast, &comment, &options, &opcname, &opcschema, &opcdefault, &opcparams, &nullsnotdistinct,\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"postgres: scanning indexes for schema %q: %w\", s.Name, err)\n\t\t}\n\t\tif !scope.hasT(table) {\n\t\t\treturn fmt.Errorf(\"table %q was not found in schema\", table)\n\t\t}\n\t\tidx, ok := names[name]\n\t\tif !ok {\n\t\t\tidx = &schema.Index{\n\t\t\t\tName:   name,\n\t\t\t\tUnique: uniq,\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&IndexType{T: typ},\n\t\t\t\t},\n\t\t\t}\n\t\t\tif sqlx.ValidString(comment) {\n\t\t\t\tidx.Attrs = append(idx.Attrs, &schema.Comment{Text: comment.String})\n\t\t\t}\n\t\t\tif sqlx.ValidString(constraints) {\n\t\t\t\tvar m map[string]string\n\t\t\t\tif err := json.Unmarshal([]byte(constraints.String), &m); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"postgres: unmarshaling index constraints: %w\", err)\n\t\t\t\t}\n\t\t\t\tfor n, t := range m {\n\t\t\t\t\tidx.AddAttrs(&Constraint{N: n, T: t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tif sqlx.ValidString(pred) {\n\t\t\t\tidx.AddAttrs(&IndexPredicate{P: pred.String})\n\t\t\t}\n\t\t\tif sqlx.ValidString(options) {\n\t\t\t\tp, err := newIndexStorage(options.String)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tidx.AddAttrs(p)\n\t\t\t}\n\t\t\tif nullsnotdistinct {\n\t\t\t\tidx.AddAttrs(&IndexNullsDistinct{V: false})\n\t\t\t}\n\t\t\tnames[name] = idx\n\t\t\tvar err error\n\t\t\tif primary {\n\t\t\t\terr = scope.setPK(table, idx)\n\t\t\t} else {\n\t\t\t\terr = scope.addIndex(table, idx)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tpart := &schema.IndexPart{SeqNo: len(idx.Parts) + 1, Desc: desc.Bool}\n\t\tif nullsfirst.Bool || nullslast.Bool {\n\t\t\tpart.Attrs = append(part.Attrs, &IndexColumnProperty{\n\t\t\t\tNullsFirst: nullsfirst.Bool,\n\t\t\t\tNullsLast:  nullslast.Bool,\n\t\t\t})\n\t\t}\n\t\tif sqlx.ValidString(exoper) {\n\t\t\tpart.AddAttrs(NewOperator(i.schema, exoper.String))\n\t\t}\n\t\tswitch {\n\t\tcase included:\n\t\t\tc, ok := scope.column(table, column.String)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"postgres: INCLUDE column %q was not found for index %q\", column.String, idx.Name)\n\t\t\t}\n\t\t\tvar include IndexInclude\n\t\t\tsqlx.Has(idx.Attrs, &include)\n\t\t\tinclude.Columns = append(include.Columns, c)\n\t\t\tschema.ReplaceOrAppend(&idx.Attrs, &include)\n\t\tcase sqlx.ValidString(column):\n\t\t\tpart.C, ok = scope.column(table, column.String)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"postgres: column %q was not found for index %q\", column.String, idx.Name)\n\t\t\t}\n\t\t\tpart.C.Indexes = append(part.C.Indexes, idx)\n\t\t\tidx.Parts = append(idx.Parts, part)\n\t\tcase sqlx.ValidString(expr):\n\t\t\tpart.X = &schema.RawExpr{\n\t\t\t\tX: expr.String,\n\t\t\t}\n\t\t\tidx.Parts = append(idx.Parts, part)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"postgres: invalid part for index %q\", idx.Name)\n\t\t}\n\t\tif err := i.mayAppendOps(part, opcschema.String, opcname.String, opcparams.String, opcdefault.Bool); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// mayAppendOps appends an operator_class attribute to the part in case it is not the default.\nfunc (i *inspect) mayAppendOps(part *schema.IndexPart, ns, name, params string, defaults bool) error {\n\tif name == \"\" || defaults && params == \"\" {\n\t\treturn nil\n\t}\n\top := &IndexOpClass{Name: name, Default: defaults}\n\tif err := op.parseParams(params); err != nil {\n\t\treturn err\n\t}\n\tpart.Attrs = append(part.Attrs, op)\n\t// Detect if the operator class reside in an external schema\n\t// and should be handled accordingly in other stages.\n\tswitch {\n\tcase\n\t\t// Schema is not defined.\n\t\tns == \"\",\n\t\t// Operator class is defined in current scope.\n\t\tns == i.schema,\n\t\t// Operator class is defined in the default search_path.\n\t\tns == \"pg_catalog\", ns == \"public\":\n\tdefault:\n\t\top.Name = fmt.Sprintf(\"%s.%s\", ns, name)\n\t}\n\treturn nil\n}\n\n// partitions builds the partition each table in the schema.\nfunc (i *inspect) partitions(s *schema.Schema) error {\n\tfor _, t := range s.Tables {\n\t\tvar d Partition\n\t\tif !sqlx.Has(t.Attrs, &d) {\n\t\t\tcontinue\n\t\t}\n\t\tswitch s := strings.ToLower(d.start); s {\n\t\tcase \"r\":\n\t\t\td.T = PartitionTypeRange\n\t\tcase \"l\":\n\t\t\td.T = PartitionTypeList\n\t\tcase \"h\":\n\t\t\td.T = PartitionTypeHash\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"postgres: unexpected partition strategy %q\", s)\n\t\t}\n\t\tidxs := strings.Split(strings.TrimSpace(d.attrs), \" \")\n\t\tif len(idxs) == 0 {\n\t\t\treturn fmt.Errorf(\"postgres: no columns/expressions were found in partition key for column %q\", t.Name)\n\t\t}\n\t\tfor i := range idxs {\n\t\t\tswitch idx, err := strconv.Atoi(idxs[i]); {\n\t\t\tcase err != nil:\n\t\t\t\treturn fmt.Errorf(\"postgres: faild parsing partition key index %q\", idxs[i])\n\t\t\t// An expression.\n\t\t\tcase idx == 0:\n\t\t\t\tj := sqlx.ExprLastIndex(d.exprs)\n\t\t\t\tif j == -1 {\n\t\t\t\t\treturn fmt.Errorf(\"postgres: no expression found in partition key: %q\", d.exprs)\n\t\t\t\t}\n\t\t\t\td.Parts = append(d.Parts, &PartitionPart{\n\t\t\t\t\tX: &schema.RawExpr{X: d.exprs[:j+1]},\n\t\t\t\t})\n\t\t\t\td.exprs = strings.TrimPrefix(d.exprs[j+1:], \", \")\n\t\t\t// A column at index idx-1.\n\t\t\tdefault:\n\t\t\t\tif idx > len(t.Columns) {\n\t\t\t\t\treturn fmt.Errorf(\"postgres: unexpected column index %d\", idx)\n\t\t\t\t}\n\t\t\t\td.Parts = append(d.Parts, &PartitionPart{\n\t\t\t\t\tC: t.Columns[idx-1],\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\tschema.ReplaceOrAppend(&t.Attrs, &d)\n\t}\n\treturn nil\n}\n\n// fks queries and appends the foreign keys of the given table.\nfunc (i *inspect) fks(ctx context.Context, s *schema.Schema) error {\n\trows, err := i.querySchema(ctx, fksQuery, s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"postgres: querying schema %q foreign keys: %w\", s.Name, err)\n\t}\n\tdefer rows.Close()\n\tif err := sqlx.TypedSchemaFKs[*ReferenceOption](s, rows); err != nil {\n\t\treturn fmt.Errorf(\"postgres: %w\", err)\n\t}\n\treturn rows.Err()\n}\n\n// checks queries and appends the check constraints of the given table.\nfunc (i *inspect) checks(ctx context.Context, s *schema.Schema) error {\n\trows, err := i.querySchema(ctx, checksQuery, s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"postgres: querying schema %q check constraints: %w\", s.Name, err)\n\t}\n\tdefer rows.Close()\n\tif err := i.addChecks(s, rows); err != nil {\n\t\treturn err\n\t}\n\treturn rows.Err()\n}\n\n// addChecks scans the rows and adds the checks to the table.\nfunc (i *inspect) addChecks(s *schema.Schema, rows *sql.Rows) error {\n\ttype tc struct{ t, n string }\n\tnames := make(map[tc]*schema.Check)\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tnoInherit                            bool\n\t\t\ttable, name, column, clause, indexes string\n\t\t)\n\t\tif err := rows.Scan(&table, &name, &clause, &column, &indexes, &noInherit); err != nil {\n\t\t\treturn fmt.Errorf(\"postgres: scanning check: %w\", err)\n\t\t}\n\t\tt, ok := s.Table(table)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"table %q was not found in schema\", table)\n\t\t}\n\t\tc, ok := t.Column(column)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"postgres: column %q was not found for check %q\", column, name)\n\t\t}\n\t\tck, ok := names[tc{t: table, n: name}]\n\t\tif !ok {\n\t\t\tck = &schema.Check{Name: name, Expr: clause, Attrs: []schema.Attr{&CheckColumns{}}}\n\t\t\tif noInherit {\n\t\t\t\tck.AddAttrs(&NoInherit{})\n\t\t\t}\n\t\t\tnames[tc{t: table, n: name}] = ck\n\t\t\tt.AddAttrs(ck)\n\t\t}\n\t\tc.AddAttrs(ck)\n\t\tattr := ck.Attrs[0].(*CheckColumns)\n\t\tattr.Columns = append(attr.Columns, column)\n\t}\n\treturn nil\n}\n\n// schemas returns the list of the schemas in the database.\nfunc (i *inspect) schemas(ctx context.Context, opts *schema.InspectRealmOption) ([]*schema.Schema, error) {\n\tvar (\n\t\targs  []any\n\t\tquery = schemasQuery\n\t)\n\tif opts != nil {\n\t\tswitch n := len(opts.Schemas); {\n\t\tcase n == 1 && opts.Schemas[0] == \"\":\n\t\t\tquery = fmt.Sprintf(schemasQueryArgs, \"= CURRENT_SCHEMA()\")\n\t\tcase n == 1 && opts.Schemas[0] != \"\":\n\t\t\tquery = fmt.Sprintf(schemasQueryArgs, \"= $1\")\n\t\t\targs = append(args, opts.Schemas[0])\n\t\tcase n > 0:\n\t\t\tquery = fmt.Sprintf(schemasQueryArgs, \"IN (\"+nArgs(0, len(opts.Schemas))+\")\")\n\t\t\tfor _, s := range opts.Schemas {\n\t\t\t\targs = append(args, s)\n\t\t\t}\n\t\t}\n\t}\n\trows, err := i.QueryContext(ctx, query, args...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"postgres: querying schemas: %w\", err)\n\t}\n\tdefer rows.Close()\n\tvar schemas []*schema.Schema\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tname    string\n\t\t\tcomment sql.NullString\n\t\t)\n\t\tif err := rows.Scan(&name, &comment); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ts := schema.New(name)\n\t\tif comment.Valid {\n\t\t\ts.SetComment(comment.String)\n\t\t}\n\t\tschemas = append(schemas, s)\n\t}\n\tif err := rows.Close(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn schemas, nil\n}\n\nfunc (i *inspect) querySchema(ctx context.Context, query string, s *schema.Schema) (*sql.Rows, error) {\n\targs := []any{s.Name}\n\tfor _, t := range s.Tables {\n\t\targs = append(args, t.Name)\n\t}\n\treturn i.QueryContext(ctx, fmt.Sprintf(query, nArgs(1, len(s.Tables))), args...)\n}\n\nfunc nArgs(start, n int) string {\n\tvar b strings.Builder\n\tfor i := 1; i <= n; i++ {\n\t\tif i > 1 {\n\t\t\tb.WriteString(\", \")\n\t\t}\n\t\tb.WriteByte('$')\n\t\tb.WriteString(strconv.Itoa(start + i))\n\t}\n\treturn b.String()\n}\n\n// A regexp to extracts the sequence name from a \"nextval\" expression.\n// nextval('<optional (quoted) schema>.<sequence name>'::regclass).\nvar reNextval = regexp.MustCompile(`(?i) *nextval\\('(?:\"?[\\w$]+\"?\\.)?\"?([\\w$]+_[\\w$]+_seq)\"?'(?:::regclass)*\\) *$`)\n\nfunc columnDefault(c *schema.Column, s string) {\n\tswitch m := reNextval.FindStringSubmatch(s); {\n\t// The definition of \"<column> <serial type>\" is equivalent to specifying:\n\t// \"<column> <int type> NOT NULL DEFAULT nextval('<table>_<column>_seq')\".\n\t// https://postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL.\n\tcase len(m) == 2:\n\t\ttt, ok := c.Type.Type.(*schema.IntegerType)\n\t\tif !ok {\n\t\t\treturn\n\t\t}\n\t\tst := &SerialType{SequenceName: m[1]}\n\t\tst.SetType(tt)\n\t\tc.Type.Raw = st.T\n\t\tc.Type.Type = st\n\tdefault:\n\t\tc.Default = defaultExpr(c.Type.Type, s)\n\t}\n}\n\nfunc defaultExpr(t schema.Type, s string) schema.Expr {\n\tswitch {\n\tcase sqlx.IsLiteralBool(s), sqlx.IsLiteralNumber(s), sqlx.IsQuoted(s, '\\''):\n\t\treturn &schema.Literal{V: s}\n\tdefault:\n\t\tvar x schema.Expr = &schema.RawExpr{X: s}\n\t\t// Try casting or fallback to raw expressions (e.g. column text[] has the default of '{}':text[]).\n\t\tif v, ok := canConvert(t, s); ok {\n\t\t\tx = &schema.Literal{V: v}\n\t\t}\n\t\treturn x\n\t}\n}\n\nfunc canConvert(t schema.Type, x string) (string, bool) {\n\ti := strings.LastIndex(x, \"::\")\n\tif i == -1 || !sqlx.IsQuoted(x[:i], '\\'') {\n\t\treturn \"\", false\n\t}\n\tq := x[0:i]\n\tx = x[1 : i-1]\n\tswitch t.(type) {\n\tcase *schema.EnumType:\n\t\treturn q, true\n\tcase *schema.BoolType:\n\t\tif sqlx.IsLiteralBool(x) {\n\t\t\treturn x, true\n\t\t}\n\tcase *schema.DecimalType, *schema.IntegerType, *schema.FloatType:\n\t\tif sqlx.IsLiteralNumber(x) {\n\t\t\treturn x, true\n\t\t}\n\tcase *ArrayType, *schema.BinaryType, *schema.JSONType, *NetworkType, *schema.SpatialType, *schema.StringType, *schema.TimeType, *schema.UUIDType, *XMLType:\n\t\treturn q, true\n\t}\n\treturn \"\", false\n}\n\ntype (\n\t// UserDefinedType defines a user-defined type attribute.\n\tUserDefinedType struct {\n\t\tschema.Type\n\t\tT string\n\t\tC string // Optional type class.\n\n\t}\n\n\t// RowType defines a composite type that represents a table row.\n\tRowType struct {\n\t\tschema.Type\n\t\tT *schema.Table // Table that this row type represents.\n\t}\n\n\t// PseudoType defines a non-column pseudo-type, such as function arguments and return types.\n\t// https://www.postgresql.org/docs/current/datatype-pseudo.html\n\tPseudoType struct {\n\t\tschema.Type\n\t\tT string // e.g., void, any, cstring, etc.\n\t}\n\n\t// OID is the object identifier as defined in the Postgres catalog.\n\tOID struct {\n\t\tschema.Attr\n\t\tV int64\n\t}\n\n\t// ArrayType defines an array type.\n\t// https://postgresql.org/docs/current/arrays.html\n\tArrayType struct {\n\t\tschema.Type        // Underlying items type (e.g. varchar(255)).\n\t\tT           string // Formatted type (e.g. int[]).\n\t}\n\n\t// BitType defines a bit type.\n\t// https://postgresql.org/docs/current/datatype-bit.html\n\tBitType struct {\n\t\tschema.Type\n\t\tT   string\n\t\tLen int64\n\t}\n\n\t// DomainType represents a domain type.\n\t// https://www.postgresql.org/docs/current/domains.html\n\tDomainType struct {\n\t\tschema.Type\n\t\tschema.Object\n\t\tT       string          // Type name.\n\t\tSchema  *schema.Schema  // Optional schema.\n\t\tNull    bool            // Nullability.\n\t\tDefault schema.Expr     // Default value.\n\t\tChecks  []*schema.Check // Check constraints.\n\t\tAttrs   []schema.Attr   // Extra attributes, such as OID.\n\t\tDeps    []schema.Object // Objects this domain depends on.\n\t}\n\n\t// CompositeType defines a composite type.\n\t// https://www.postgresql.org/docs/current/rowtypes.html\n\tCompositeType struct {\n\t\tschema.Type\n\t\tschema.Object\n\t\tT      string           // Type name.\n\t\tSchema *schema.Schema   // Optional schema.\n\t\tFields []*schema.Column // Type fields, also known as attributes/columns.\n\t\tAttrs  []schema.Attr    // Extra attributes, such as OID.\n\t\tDeps   []schema.Object  // Objects this domain depends on.\n\t}\n\n\t// IntervalType defines an interval type.\n\t// https://postgresql.org/docs/current/datatype-datetime.html\n\tIntervalType struct {\n\t\tschema.Type\n\t\tT         string // Type name.\n\t\tF         string // Optional field. YEAR, MONTH, ..., MINUTE TO SECOND.\n\t\tPrecision *int   // Optional precision.\n\t}\n\n\t// A NetworkType defines a network type.\n\t// https://postgresql.org/docs/current/datatype-net-types.html\n\tNetworkType struct {\n\t\tschema.Type\n\t\tT   string\n\t\tLen int64\n\t}\n\n\t// A CurrencyType defines a currency type.\n\tCurrencyType struct {\n\t\tschema.Type\n\t\tT string\n\t}\n\n\t// A RangeType defines a range type.\n\t// https://www.postgresql.org/docs/current/rangetypes.html\n\tRangeType struct {\n\t\tschema.Type\n\t\tT string\n\t}\n\n\t// A SerialType defines a serial type.\n\t// https://postgresql.org/docs/current/datatype-numeric.html#DATATYPE-SERIAL\n\tSerialType struct {\n\t\tschema.Type\n\t\tT         string\n\t\tPrecision int\n\t\t// SequenceName holds the inspected sequence name attached to the column.\n\t\t// It defaults to <Table>_<Column>_seq when the column is created, but may\n\t\t// be different in case the table or the column was renamed.\n\t\tSequenceName string\n\t}\n\n\t// A TextSearchType defines full text search types.\n\t// https://www.postgresql.org/docs/current/datatype-textsearch.html\n\tTextSearchType struct {\n\t\tschema.Type\n\t\tT string\n\t}\n\n\t// UUIDType is alias to schema.UUIDType.\n\t// Defined here for backward compatibility reasons.\n\tUUIDType = schema.UUIDType\n\n\t// OIDType defines an object identifier type.\n\tOIDType struct {\n\t\tschema.Type\n\t\tT string\n\t}\n\n\t// A XMLType defines an XML type.\n\tXMLType struct {\n\t\tschema.Type\n\t\tT string\n\t}\n\n\t// ConvertUsing describes the USING clause to convert\n\t// one type to another.\n\tConvertUsing struct {\n\t\tschema.Clause\n\t\tX string // Conversion expression.\n\t}\n\n\t// Constraint describes a postgres constraint.\n\t// https://postgresql.org/docs/current/catalog-pg-constraint.html\n\tConstraint struct {\n\t\tschema.Attr\n\t\tN string // constraint name\n\t\tT string // c, f, p, u, t, x.\n\t}\n\n\t// Operator describes an operator.\n\t// https://www.postgresql.org/docs/current/sql-createoperator.html\n\tOperator struct {\n\t\tschema.Attr\n\t\tschema.Object\n\t\t// Schema where the operator is defined. If nil, the operator\n\t\t// is not managed by the current scope.\n\t\tSchema *schema.Schema\n\t\t// Operator name. Might include the schema name if the schema\n\t\t// is not managed by the current scope or extension based.\n\t\t// e.g., \"public.&&\".\n\t\tName  string\n\t\tAttrs []schema.Attr\n\t}\n\n\t// Sequence defines (the supported) sequence options.\n\t// https://postgresql.org/docs/current/sql-createsequence.html\n\tSequence struct {\n\t\tschema.Object\n\t\t// Fields used by the Identity schema attribute.\n\t\tStart     int64\n\t\tIncrement int64\n\t\t// Last sequence value written to disk.\n\t\t// https://postgresql.org/docs/current/view-pg-sequences.html.\n\t\tLast int64\n\n\t\t// Field used when defining and managing independent\n\t\t// sequences (not part of IDENTITY or serial columns).\n\t\tName     string         // Sequence name.\n\t\tSchema   *schema.Schema // Optional schema.\n\t\tType     schema.Type    // Sequence type.\n\t\tCache    int64          // Cache size.\n\t\tMin, Max *int64         // Min and max values.\n\t\tCycle    bool           // Whether the sequence cycles.\n\t\tAttrs    []schema.Attr  // Additional attributes (e.g., comments),\n\t\tOwner    struct {       // Optional owner of the sequence.\n\t\t\tT *schema.Table\n\t\t\tC *schema.Column\n\t\t}\n\t}\n\n\t// Identity defines an identity column.\n\tIdentity struct {\n\t\tschema.Attr\n\t\tGeneration string // ALWAYS, BY DEFAULT.\n\t\tSequence   *Sequence\n\t}\n\n\t// IndexType represents an index type.\n\t// https://postgresql.org/docs/current/indexes-types.html\n\tIndexType struct {\n\t\tschema.Attr\n\t\tT string // BTREE, BRIN, HASH, GiST, SP-GiST, GIN.\n\t}\n\n\t// IndexPredicate describes a partial index predicate.\n\t// https://postgresql.org/docs/current/catalog-pg-index.html\n\tIndexPredicate struct {\n\t\tschema.Attr\n\t\tP string\n\t}\n\n\t// IndexColumnProperty describes an index column property.\n\t// https://postgresql.org/docs/current/functions-info.html#FUNCTIONS-INFO-INDEX-COLUMN-PROPS\n\tIndexColumnProperty struct {\n\t\tschema.Attr\n\t\t// NullsFirst defaults to true for DESC indexes.\n\t\tNullsFirst bool\n\t\t// NullsLast defaults to true for ASC indexes.\n\t\tNullsLast bool\n\t}\n\n\t// IndexStorageParams describes index storage parameters add with the WITH clause.\n\t// https://postgresql.org/docs/current/sql-createindex.html#SQL-CREATEINDEX-STORAGE-PARAMETERS\n\tIndexStorageParams struct {\n\t\tschema.Attr\n\t\t// AutoSummarize defines the authsummarize storage parameter.\n\t\tAutoSummarize bool\n\t\t// PagesPerRange defines pages_per_range storage\n\t\t// parameter for BRIN indexes. Defaults to 128.\n\t\tPagesPerRange int64\n\t}\n\n\t// IndexInclude describes the INCLUDE clause allows specifying\n\t// a list of column which added to the index as non-key columns.\n\t// https://www.postgresql.org/docs/current/sql-createindex.html\n\tIndexInclude struct {\n\t\tschema.Attr\n\t\tColumns []*schema.Column\n\t}\n\n\t// IndexOpClass describers operator class of the index part.\n\t// https://www.postgresql.org/docs/current/indexes-opclass.html.\n\tIndexOpClass struct {\n\t\tschema.Attr\n\t\tName    string                  // Name of the operator class. Qualified if schema is not the default, and required.\n\t\tDefault bool                    // If it is the default operator class.\n\t\tParams  []struct{ N, V string } // Optional parameters.\n\t}\n\n\t// IndexNullsDistinct describes the NULLS [NOT] DISTINCT clause.\n\tIndexNullsDistinct struct {\n\t\tschema.Attr\n\t\tV bool // NULLS [NOT] DISTINCT. Defaults to true.\n\t}\n\n\t// Concurrently describes the CONCURRENTLY clause to instruct Postgres to\n\t// build or drop the index concurrently without blocking the current table.\n\t// https://www.postgresql.org/docs/current/sql-createindex.html#SQL-CREATEINDEX-CONCURRENTLY\n\tConcurrently struct {\n\t\tschema.Clause\n\t}\n\n\t// NotValid describes the NOT VALID clause for the creation\n\t// of check and foreign-key constraints.\n\tNotValid struct {\n\t\tschema.Clause\n\t}\n\n\t// NoInherit attribute defines the NO INHERIT flag for CHECK constraint.\n\t// https://postgresql.org/docs/current/catalog-pg-constraint.html\n\tNoInherit struct {\n\t\tschema.Attr\n\t}\n\n\t// CheckColumns attribute hold the column named used by the CHECK constraints.\n\t// This attribute is added on inspection for internal usage and has no meaning\n\t// on migration.\n\tCheckColumns struct {\n\t\tschema.Attr\n\t\tColumns []string\n\t}\n\n\t// Partition defines the spec of a partitioned table.\n\tPartition struct {\n\t\tschema.Attr\n\t\t// T defines the type/strategy of the partition.\n\t\t// Can be one of: RANGE, LIST, HASH.\n\t\tT string\n\t\t// Partition parts. The additional attributes\n\t\t// on each part can be used to control collation.\n\t\tParts []*PartitionPart\n\n\t\t// Internal info returned from pg_partitioned_table.\n\t\tstart, attrs, exprs string\n\t}\n\n\t// An PartitionPart represents an index part that\n\t// can be either an expression or a column.\n\tPartitionPart struct {\n\t\tX     schema.Expr\n\t\tC     *schema.Column\n\t\tAttrs []schema.Attr\n\t}\n\n\t// Cascade describes that a CASCADE clause should be added to the DROP [TABLE|SCHEMA]\n\t// operation. Note, this clause is automatically added to DROP SCHEMA by the planner.\n\tCascade struct {\n\t\tschema.Clause\n\t}\n\n\t// ReferenceOption describes the ON DELETE and ON UPDATE options for foreign keys.\n\tReferenceOption schema.ReferenceOption\n)\n\nvar _ specutil.RefNamer = (*DomainType)(nil)\n\n// Ref returns a reference to the domain type.\nfunc (d *DomainType) Ref() *schemahcl.Ref {\n\treturn specutil.ObjectRef(d.Schema, d)\n}\n\n// SpecType returns the type of the domain.\nfunc (d *DomainType) SpecType() string {\n\treturn \"domain\"\n}\n\n// SpecName returns the name of the domain.\nfunc (d *DomainType) SpecName() string {\n\treturn d.T\n}\n\n// Underlying returns the underlying type of the domain.\nfunc (d *DomainType) Underlying() schema.Type {\n\treturn d.Type\n}\n\n// SpecType returns the type of the composite type.\nfunc (c *CompositeType) SpecType() string {\n\treturn \"composite\"\n}\n\n// SpecName returns the name of the composite type.\nfunc (c *CompositeType) SpecName() string {\n\treturn c.T\n}\n\n// Underlying returns the underlying type of the array.\nfunc (a *ArrayType) Underlying() schema.Type {\n\treturn a.Type\n}\n\n// String implements fmt.Stringer interface.\nfunc (o ReferenceOption) String() string {\n\treturn string(o)\n}\n\n// Scan implements sql.Scanner interface.\nfunc (o *ReferenceOption) Scan(v any) error {\n\tvar s sql.NullString\n\tif err := s.Scan(v); err != nil {\n\t\treturn err\n\t}\n\tswitch strings.ToLower(s.String) {\n\tcase \"a\":\n\t\t*o = ReferenceOption(schema.NoAction)\n\tcase \"r\":\n\t\t*o = ReferenceOption(schema.Restrict)\n\tcase \"c\":\n\t\t*o = ReferenceOption(schema.Cascade)\n\tcase \"n\":\n\t\t*o = ReferenceOption(schema.SetNull)\n\tcase \"d\":\n\t\t*o = ReferenceOption(schema.SetDefault)\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown reference option: %q\", s.String)\n\t}\n\treturn nil\n}\n\n// IsUnique reports if the type is a unique constraint.\nfunc (c Constraint) IsUnique() bool { return strings.ToLower(c.T) == \"u\" }\n\n// IsExclude reports if the type is an exclude constraint.\nfunc (c Constraint) IsExclude() bool { return strings.ToLower(c.T) == \"x\" }\n\n// UniqueConstraint returns constraint with type \"u\".\nfunc UniqueConstraint(name string) *Constraint {\n\treturn &Constraint{T: \"u\", N: name}\n}\n\n// ExcludeConstraint returns constraint with type \"x\".\nfunc ExcludeConstraint(name string) *Constraint {\n\treturn &Constraint{T: \"x\", N: name}\n}\n\n// NewOperator returns the string representation of the operator.\nfunc NewOperator(scope string, name string) *Operator {\n\t// When scanned from the database, the operator is returned as: \"<schema>.<operator>\".\n\t// The common case is that operators are the default and defined in pg_catalog, or are\n\t// installed by extensions.\n\tif parts := strings.FieldsFunc(name, func(r rune) bool {\n\t\treturn r == '.'\n\t}); len(parts) == 2 && (scope == \"\" || parts[0] == \"pg_catalog\" || parts[0] == scope) {\n\t\treturn &Operator{Name: parts[1]}\n\t}\n\treturn &Operator{Name: name}\n}\n\n// IntegerType returns the underlying integer type this serial type represents.\nfunc (s *SerialType) IntegerType() *schema.IntegerType {\n\tt := &schema.IntegerType{T: TypeInteger}\n\tswitch s.T {\n\tcase TypeSerial2, TypeSmallSerial:\n\t\tt.T = TypeSmallInt\n\tcase TypeSerial8, TypeBigSerial:\n\t\tt.T = TypeBigInt\n\t}\n\treturn t\n}\n\n// SetType sets the serial type from the given integer type.\nfunc (s *SerialType) SetType(t *schema.IntegerType) {\n\tswitch t.T {\n\tcase TypeSmallInt, TypeInt2:\n\t\ts.T = TypeSmallSerial\n\tcase TypeInteger, TypeInt4, TypeInt:\n\t\ts.T = TypeSerial\n\tcase TypeBigInt, TypeInt8:\n\t\ts.T = TypeBigSerial\n\t}\n}\n\n// sequence returns the inspected name of the sequence\n// or the standard name defined by postgres.\nfunc (s *SerialType) sequence(t *schema.Table, c *schema.Column) string {\n\tif s.SequenceName != \"\" {\n\t\treturn s.SequenceName\n\t}\n\treturn fmt.Sprintf(\"%s_%s_seq\", t.Name, c.Name)\n}\n\nvar (\n\topsOnce    sync.Once\n\tdefaultOps map[postgresop.Class]bool\n)\n\n// DefaultFor reports if the operator_class is the default for the index part.\nfunc (o *IndexOpClass) DefaultFor(idx *schema.Index, part *schema.IndexPart) (bool, error) {\n\t// Explicitly defined as the default (Usually, it comes from the inspection).\n\tif o.Default && len(o.Params) == 0 {\n\t\treturn true, nil\n\t}\n\tit := &IndexType{T: IndexTypeBTree}\n\tif sqlx.Has(idx.Attrs, it) {\n\t\tit.T = strings.ToUpper(it.T)\n\t}\n\t// The key type must be known to check if it is the default op_class.\n\tif part.X != nil || len(o.Params) > 0 {\n\t\treturn false, nil\n\t}\n\topsOnce.Do(func() {\n\t\tdefaultOps = make(map[postgresop.Class]bool, len(postgresop.Classes))\n\t\tfor _, op := range postgresop.Classes {\n\t\t\tif op.Default {\n\t\t\t\tdefaultOps[postgresop.Class{Name: op.Name, Method: op.Method, Type: op.Type}] = true\n\t\t\t}\n\t\t}\n\t})\n\tvar (\n\t\tt   string\n\t\terr error\n\t)\n\tswitch typ := part.C.Type.Type.(type) {\n\tcase *schema.EnumType:\n\t\tt = \"anyenum\"\n\tcase *ArrayType:\n\t\tt = \"anyarray\"\n\tdefault:\n\t\tt, err = FormatType(typ)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"postgres: format operator-class type %T: %w\", typ, err)\n\t\t}\n\t}\n\treturn defaultOps[postgresop.Class{Name: o.Name, Method: it.T, Type: t}], nil\n}\n\n// Equal reports whether o and x are the same operator class.\nfunc (o *IndexOpClass) Equal(x *IndexOpClass) bool {\n\tif o.Name != x.Name || o.Default != x.Default || len(o.Params) != len(x.Params) {\n\t\treturn false\n\t}\n\tfor i := range o.Params {\n\t\tif o.Params[i].N != x.Params[i].N || o.Params[i].V != x.Params[i].V {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// String returns the string representation of the operator class.\nfunc (o *IndexOpClass) String() string {\n\tif len(o.Params) == 0 {\n\t\treturn o.Name\n\t}\n\tvar b strings.Builder\n\tb.WriteString(o.Name)\n\tb.WriteString(\"(\")\n\tfor i, p := range o.Params {\n\t\tif i > 0 {\n\t\t\tb.WriteString(\", \")\n\t\t}\n\t\tb.WriteString(p.N)\n\t\tb.WriteString(\"=\")\n\t\tb.WriteString(p.V)\n\t}\n\tb.WriteString(\")\")\n\treturn b.String()\n}\n\n// UnmarshalText parses the operator class from its string representation.\nfunc (o *IndexOpClass) UnmarshalText(text []byte) error {\n\ti := bytes.IndexByte(text, '(')\n\tif i == -1 {\n\t\to.Name = string(text)\n\t\treturn nil\n\t}\n\to.Name = string(text[:i])\n\treturn o.parseParams(string(text[i:]))\n}\n\n// parseParams parses index class parameters defined in HCL or returned\n// from the database. For example: '{k=v}', '(k1=v1,k2=v2)'.\nfunc (o *IndexOpClass) parseParams(kv string) error {\n\tswitch {\n\tcase kv == \"\":\n\tcase strings.HasPrefix(kv, \"(\") && strings.HasSuffix(kv, \")\"), strings.HasPrefix(kv, \"{\") && strings.HasSuffix(kv, \"}\"):\n\t\tfor _, e := range strings.Split(kv[1:len(kv)-1], \",\") {\n\t\t\tif kv := strings.Split(strings.TrimSpace(e), \"=\"); len(kv) == 2 {\n\t\t\t\to.Params = append(o.Params, struct{ N, V string }{N: kv[0], V: kv[1]})\n\t\t\t}\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"postgres: unexpected operator class parameters format: %q\", kv)\n\t}\n\treturn nil\n}\n\n// newIndexStorage parses and returns the index storage parameters.\nfunc newIndexStorage(opts string) (*IndexStorageParams, error) {\n\tparams := &IndexStorageParams{}\n\tfor _, p := range strings.Split(strings.Trim(opts, \"{}\"), \",\") {\n\t\tkv := strings.Split(p, \"=\")\n\t\tif len(kv) != 2 {\n\t\t\treturn nil, fmt.Errorf(\"invalid index storage parameter: %s\", p)\n\t\t}\n\t\tswitch kv[0] {\n\t\tcase \"autosummarize\":\n\t\t\tb, err := strconv.ParseBool(kv[1])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed parsing autosummarize %q: %w\", kv[1], err)\n\t\t\t}\n\t\t\tparams.AutoSummarize = b\n\t\tcase \"pages_per_range\":\n\t\t\ti, err := strconv.ParseInt(kv[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed parsing pages_per_range %q: %w\", kv[1], err)\n\t\t\t}\n\t\t\tparams.PagesPerRange = i\n\t\t}\n\t}\n\treturn params, nil\n}\n\n// reFmtType extracts the formatted type and an option schema qualifier.\nvar reFmtType = regexp.MustCompile(`^(?:(\".+\"|\\w+)\\.)?(\".+\"|\\w+)$`)\n\n// parseFmtType parses the formatted type returned from pg_catalog.format_type\n// and extract the schema and type name.\nfunc parseFmtType(t string) (s, n string) {\n\tn = t\n\tparts := reFmtType.FindStringSubmatch(t)\n\tr := func(s string) string {\n\t\ts = strings.ReplaceAll(s, `\"\"`, `\"`)\n\t\tif len(s) > 1 && s[0] == '\"' && s[len(s)-1] == '\"' {\n\t\t\ts = s[1 : len(s)-1]\n\t\t}\n\t\treturn s\n\t}\n\tif len(parts) > 1 {\n\t\ts = r(parts[1])\n\t}\n\tif len(parts) > 2 {\n\t\tn = r(parts[2])\n\t}\n\treturn s, n\n}\n\nconst (\n\t// Query to list runtime parameters.\n\tparamsQuery = `SELECT current_setting('server_version_num'), current_setting('default_table_access_method', true), current_setting('crdb_version', true)`\n\n\t// Query to list database schemas.\n\tschemasQuery = `\nSELECT\n\tnspname AS schema_name,\n\tpg_catalog.obj_description(ns.oid) AS comment\nFROM\n\tpg_catalog.pg_namespace ns\n\tLEFT JOIN pg_depend AS dep ON dep.classid = 'pg_catalog.pg_namespace'::regclass::oid AND dep.objid = ns.oid AND dep.deptype = 'e'\nWHERE\n\tnspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast', 'crdb_internal', 'pg_extension')\n\tAND nspname NOT LIKE 'pg_%temp_%'\n\tAND dep.objid IS NULL\nORDER BY\n    nspname`\n\n\t// Query to list database schemas.\n\tschemasQueryArgs = `\nSELECT\n\tnspname AS schema_name,\n\tpg_catalog.obj_description(ns.oid) AS comment\nFROM\n\tpg_catalog.pg_namespace ns\n\tLEFT JOIN pg_depend AS dep ON dep.classid = 'pg_catalog.pg_namespace'::regclass::oid AND dep.objid = ns.oid AND dep.deptype = 'e'\nWHERE\n\tnspname %s\n\tAND dep.objid IS NULL\nORDER BY\n    nspname`\n\n\t// Query to list table columns.\n\tcolumnsQuery = `\nSELECT\n\tt1.table_name,\n\tt1.column_name,\n\tt1.data_type,\n\tpg_catalog.format_type(a.atttypid, a.atttypmod) AS format_type,\n\tt1.is_nullable,\n\tt1.column_default,\n\tt1.character_maximum_length,\n\tt1.numeric_precision,\n\tt1.datetime_precision,\n\tt1.numeric_scale,\n\tt1.interval_type,\n\tt1.character_set_name,\n\tt1.collation_name,\n\tt1.is_identity,\n\tt1.identity_start,\n\tt1.identity_increment,\n\t(CASE WHEN t1.is_identity = 'YES' THEN (SELECT last_value FROM pg_sequences WHERE quote_ident(schemaname) || '.' || quote_ident(sequencename) = pg_get_serial_sequence(quote_ident(t1.table_schema) || '.' || quote_ident(t1.table_name), t1.column_name)) END) AS identity_last,\n\tt1.identity_generation,\n\tt1.generation_expression,\n\tcol_description(t3.oid, \"ordinal_position\") AS comment,\n\tt4.typtype,\n\tt4.typelem,\n\tt4.oid,\n\ta.attnum\nFROM\n\t\"information_schema\".\"columns\" AS t1\n\tJOIN pg_catalog.pg_namespace AS t2 ON t2.nspname = t1.table_schema\n\tJOIN pg_catalog.pg_class AS t3 ON t3.relnamespace = t2.oid AND t3.relname = t1.table_name\n\tJOIN pg_catalog.pg_attribute AS a ON a.attrelid = t3.oid AND a.attname = t1.column_name\n\tLEFT JOIN pg_catalog.pg_type AS t4 ON t4.oid = a.atttypid\nWHERE\n\tt1.table_schema = $1 AND t1.table_name IN (%s)\nORDER BY\n\tt1.table_name, t1.ordinal_position\n`\n\t// Query to list enum values.\n\tenumsQuery = `\nSELECT\n\tn.nspname AS schema_name,\n\te.enumtypid AS enum_id,\n\tt.typname AS enum_name,\n\te.enumlabel AS enum_value\nFROM\n\tpg_enum e\n\tJOIN pg_type t ON e.enumtypid = t.oid\n\tJOIN pg_namespace n ON t.typnamespace = n.oid\nWHERE\n    n.nspname IN (%s)\nORDER BY\n    n.nspname, e.enumtypid, e.enumsortorder\n`\n\t// Query to list foreign-keys.\n\tfksQuery = `\nSELECT \n    fk.constraint_name,\n    fk.table_name,\n    a1.attname AS column_name,\n    fk.schema_name,\n    fk.referenced_table_name,\n    a2.attname AS referenced_column_name,\n    fk.referenced_schema_name,\n    fk.confupdtype,\n    fk.confdeltype\n\tFROM \n\t    (\n\t    \tSELECT\n\t      \t\tcon.conname AS constraint_name,\n\t      \t\tcon.conrelid,\n\t      \t\tcon.confrelid,\n\t      \t\tt1.relname AS table_name,\n\t      \t\tns1.nspname AS schema_name,\n      \t\t\tt2.relname AS referenced_table_name,\n\t      \t\tns2.nspname AS referenced_schema_name,\n\t      \t\tgenerate_series(1,array_length(con.conkey,1)) as ord,\n\t      \t\tunnest(con.conkey) AS conkey,\n\t      \t\tunnest(con.confkey) AS confkey,\n\t      \t\tcon.confupdtype,\n\t      \t\tcon.confdeltype\n\t    \tFROM pg_constraint con\n\t    \tJOIN pg_class t1 ON t1.oid = con.conrelid\n\t    \tJOIN pg_class t2 ON t2.oid = con.confrelid\n\t    \tJOIN pg_namespace ns1 on t1.relnamespace = ns1.oid\n\t    \tJOIN pg_namespace ns2 on t2.relnamespace = ns2.oid\n\t    \tWHERE ns1.nspname = $1\n\t    \tAND t1.relname IN (%s)\n\t    \tAND con.contype = 'f'\n\t) AS fk\n\tJOIN pg_attribute a1 ON a1.attnum = fk.conkey AND a1.attrelid = fk.conrelid\n\tJOIN pg_attribute a2 ON a2.attnum = fk.confkey AND a2.attrelid = fk.confrelid\n\tORDER BY\n\t    fk.conrelid, fk.constraint_name, fk.ord\n`\n\n\t// Query to list table check constraints.\n\tchecksQuery = `\nSELECT\n\trel.relname AS table_name,\n\tt1.conname AS constraint_name,\n\tpg_get_expr(t1.conbin, t1.conrelid) as expression,\n\tt2.attname as column_name,\n\tt1.conkey as column_indexes,\n\tt1.connoinherit as no_inherit\nFROM\n\tpg_constraint t1\n\tJOIN pg_attribute t2\n\tON t2.attrelid = t1.conrelid\n\tAND t2.attnum = ANY (t1.conkey)\n\tJOIN pg_class rel\n\tON rel.oid = t1.conrelid\n\tJOIN pg_namespace nsp\n\tON nsp.oid = t1.connamespace\nWHERE\n\tt1.contype = 'c'\n\tAND nsp.nspname = $1\n\tAND rel.relname IN (%s)\nORDER BY\n\tt1.conname, array_position(t1.conkey, t2.attnum)\n`\n)\n\nvar (\n\tindexesBelow11   = fmt.Sprintf(indexesQueryTmpl, \"false\", \"false\", \"%s\")\n\tindexesAbove11   = fmt.Sprintf(indexesQueryTmpl, \"(a.attname <> '' AND idx.indnatts > idx.indnkeyatts AND idx.ord > idx.indnkeyatts)\", \"false\", \"%s\")\n\tindexesAbove15   = fmt.Sprintf(indexesQueryTmpl, \"(a.attname <> '' AND idx.indnatts > idx.indnkeyatts AND idx.ord > idx.indnkeyatts)\", \"idx.indnullsnotdistinct\", \"%s\")\n\tindexesQueryTmpl = `\nSELECT\n\tt.relname AS table_name,\n\ti.relname AS index_name,\n\tam.amname AS index_type,\n\ta.attname AS column_name,\n\t%s AS included,\n\tidx.indisprimary AS primary,\n\tidx.indisunique AS unique,\n\t(CASE WHEN idx.indisexclusion THEN (SELECT conexclop[idx.ord]::regoper FROM pg_constraint WHERE conindid = idx.indexrelid) END) AS excoper,\n\tcon.nametypes AS constraints,\n\tpg_get_expr(idx.indpred, idx.indrelid) AS predicate,\n\tpg_get_indexdef(idx.indexrelid, idx.ord, false) AS expression,\n\tpg_index_column_has_property(idx.indexrelid, idx.ord, 'desc') AS isdesc,\n\tpg_index_column_has_property(idx.indexrelid, idx.ord, 'nulls_first') AS nulls_first,\n\tpg_index_column_has_property(idx.indexrelid, idx.ord, 'nulls_last') AS nulls_last,\n\tobj_description(i.oid, 'pg_class') AS comment,\n\ti.reloptions AS options,\n\top.opcname AS opclass_name,\n\top.opcnamespace::regnamespace::text AS opclass_schema,\n\top.opcdefault AS opclass_default,\n\ta2.attoptions AS opclass_params,\n    %s AS indnullsnotdistinct\nFROM\n\t(\n\t\tselect\n\t\t\t*,\n\t\t\tgenerate_series(1,array_length(i.indkey,1)) as ord,\n\t\t\tunnest(i.indkey) AS key\n\t\tfrom pg_index i\n\t) idx\n\tJOIN pg_class i ON i.oid = idx.indexrelid\n\tJOIN pg_class t ON t.oid = idx.indrelid\n\tJOIN pg_namespace n ON n.oid = t.relnamespace\n\tLEFT JOIN (\n\t    select conindid, jsonb_object_agg(conname, contype) AS nametypes\n\t    from pg_constraint\n\t    group by conindid\n\t) con ON con.conindid = idx.indexrelid\n\tLEFT JOIN pg_attribute a ON (a.attrelid, a.attnum) = (idx.indrelid, idx.key)\n\tJOIN pg_am am ON am.oid = i.relam\n\tLEFT JOIN pg_opclass op ON op.oid = idx.indclass[idx.ord-1]\n\tLEFT JOIN pg_attribute a2 ON (a2.attrelid, a2.attnum) = (idx.indexrelid, idx.ord)\nWHERE\n\tn.nspname = $1\n\tAND t.relname IN (%s)\nORDER BY\n\ttable_name, index_name, idx.ord\n`\n)\n"
  },
  {
    "path": "sql/postgres/inspect_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/internal/sqltest\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\n// Single table queries used by the different tests.\nvar (\n\tqueryFKs         = sqltest.Escape(fmt.Sprintf(fksQuery, \"$2\"))\n\tqueryEnums       = sqltest.Escape(fmt.Sprintf(enumsQuery, \"$1\"))\n\tqueryTables      = sqltest.Escape(fmt.Sprintf(tablesQuery, \"$1\"))\n\tqueryChecks      = sqltest.Escape(fmt.Sprintf(checksQuery, \"$2\"))\n\tqueryColumns     = sqltest.Escape(fmt.Sprintf(columnsQuery, \"$2\"))\n\tqueryCRDBColumns = sqltest.Escape(fmt.Sprintf(crdbColumnsQuery, \"$2\"))\n\tqueryIndexes     = sqltest.Escape(fmt.Sprintf(indexesAbove15, \"$2\"))\n\tqueryCRDBIndexes = sqltest.Escape(fmt.Sprintf(crdbIndexesQuery, \"$2\"))\n)\n\nfunc TestDriver_InspectTable(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tbefore func(mock)\n\t\texpect func(*require.Assertions, *schema.Table, error)\n\t}{\n\t\t{\n\t\t\tname: \"column types\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(enumsQuery, \"$1\"))).\n\t\t\t\t\tWithArgs(\"public\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n schema_name | enum_id | type    | enum_value\n-------------+---------+---------+------------\n public      |   16774 |  state  | on\n public      |   16774 |  state  | off\n public      |   16775 |  status | unknown\n`))\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n table_name  |  column_name |          data_type          |  formatted          | is_nullable |         column_default                 | character_maximum_length | numeric_precision | datetime_precision | numeric_scale |    interval_type    | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem |  oid  |  attnum  \n-------------+--------------+-----------------------------+---------------------|-------------+----------------------------------------+--------------------------+-------------------+--------------------+---------------+---------------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+-------+-------\n users       |  id          | bigint                      | int8                | NO          |                                        |                          |                64 |                    |             0 |                     |                    |                | YES         |      100       |          1         |          1       |    BY DEFAULT       |                       |         | b       |         |    20 |  \n users       |  rank        | integer                     | int4                | YES         |                                        |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       | rank    | b       |         |    23 |  \n users       |  c1          | smallint                    | int2                | NO          |           1000                         |                          |                16 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    21 |  \n users       |  c2          | bit                         | bit                 | NO          |                                        |                        1 |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1560 |  \n users       |  c3          | bit varying                 | varbit              | NO          |                                        |                       10 |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1562 |  \n users       |  c4          | boolean                     | bool                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    16 |  \n users       |  c5          | bytea                       | bytea               | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    17 |  \n users       |  c6          | character                   | bpchar              | NO          |                                        |                      100 |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1042 |  \n users       |  c7          | character varying           | varchar             | NO          | 'logged_in'::character varying         |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1043 |  \n users       |  c8          | cidr                        | cidr                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   650 |  \n users       |  c9          | circle                      | circle              | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   718 |  \n users       |  c10         | date                        | date                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1082 |  \n users       |  c11         | time with time zone         | timetz              | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1266 |  \n users       |  c12         | double precision            | float8              | NO          |                                        |                          |                53 |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   701 |  \n users       |  c13         | real                        | float4              | NO          |           random()                     |                          |                24 |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   700 |  \n users       |  c14         | json                        | json                | NO          |           '{}'::json                   |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   114 |  \n users       |  c15         | jsonb                       | jsonb               | NO          |           '{}'::jsonb                  |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  3802 |  \n users       |  c16         | money                       | money               | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   790 |  \n users       |  c17         | numeric                     | numeric             | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1700 |  \n users       |  c18         | numeric                     | numeric             | NO          |                                        |                          |                 4 |                    |             4 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1700 |  \n users       |  c19         | integer                     | int4                | NO          | nextval('t1_c19_seq'::regclass)        |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23 |  \n users       |  c20         | uuid                        | uuid                | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  2950 |  \n users       |  c21         | xml                         | xml                 | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   142 |  \n users       |  c22         | ARRAY                       | integer[]           | YES         |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1007 |  \n users       |  c23         | USER-DEFINED                | ltree               | YES         |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         | 16535 |  \n users       |  c24         | USER-DEFINED                | state               | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | e       |         | 16774 |  \n users       |  c25         | timestamp without time zone | timestamp           | NO          |            now()                       |                          |                   |                  4 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1114 |  \n users       |  c26         | timestamp with time zone    | timestamptz         | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1184 |  \n users       |  c27         | time without time zone      | time                | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1266 |  \n users       |  c28         | int                         | int8                | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |        (c1 + c2)      |         | b       |         |  1267 |  \n users       |  c29         | interval                    | interval            | NO          |                                        |                          |                   |                  6 |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1268 |  \n users       |  c30         | interval                    | interval            | NO          |                                        |                          |                   |                  6 |               |        MONTH        |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1269 |  \n users       |  c31         | interval                    | interval            | NO          |                                        |                          |                   |                  6 |               | MINUTE TO SECOND(6) |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  1233 |  \n users       |  c32         | bigint                      | int4                | NO          | nextval('public.t1_c32_seq'::regclass) |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23 |  \n users       |  c33         | USER-DEFINED                | status              | NO          |  'unknown'::test.\"status\"\".\"           |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | e       |         | 16775 |  \n users       |  c34         | ARRAY                       | state[]             | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |  16774  | 16779 |  \n users       |  c35         | character                   | domain_char         | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | d       |  16774  | 16779 |  \n users       |  c36         | tsvector                    | tsvector            | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |  16774  | 16779 |  \n users       |  c37         | tsquery                     | tsquery             | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |  16774  | 16779 |  \n users       |  c38         | datemultirange              | datemultirange      | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | m       |         | 4535  |  \n users       |  c39         | numrange                    | numrange            | NO          |                                        |                          |                   |                    |               |                     |                    |                | NO          |                |                    |                  |                     |                       |         | m       |         | 4536  |  \n users       |  c40         | smallint                    | int4                | NO          | nextval('\"Users_c40_seq\"'::regclass)   |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23 |  \n users       |  c41         | smallint                    | int4                | NO          | nextval('foo.\"T_C40_seq\"'::regclass)   |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23 |  \n users       |  c42         | smallint                    | int4                | NO          | nextval('\"F\".\"T_C40_seq\"'::regclass)   |                          |                32 |                    |             0 |                     |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23 |  \n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t\tm.noChecks()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\tstateE := &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\"}, Schema: t.Schema}\n\t\t\t\tstatusE := &schema.EnumType{T: \"status\", Values: []string{\"unknown\"}, Schema: t.Schema}\n\t\t\t\texpected := []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&Identity{Generation: \"BY DEFAULT\", Sequence: &Sequence{Start: 100, Increment: 1, Last: 1}}}},\n\t\t\t\t\t{Name: \"rank\", Type: &schema.ColumnType{Raw: \"integer\", Null: true, Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{&schema.Comment{Text: \"rank\"}}},\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"smallint\", Type: &schema.IntegerType{T: \"smallint\"}}, Default: &schema.Literal{V: \"1000\"}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"bit\", Type: &BitType{T: \"bit\", Len: 1}}},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"bit varying\", Type: &BitType{T: \"bit varying\", Len: 10}}},\n\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Raw: \"boolean\", Type: &schema.BoolType{T: \"boolean\"}}},\n\t\t\t\t\t{Name: \"c5\", Type: &schema.ColumnType{Raw: \"bytea\", Type: &schema.BinaryType{T: \"bytea\"}}},\n\t\t\t\t\t{Name: \"c6\", Type: &schema.ColumnType{Raw: \"character\", Type: &schema.StringType{T: \"character\", Size: 100}}},\n\t\t\t\t\t{Name: \"c7\", Type: &schema.ColumnType{Raw: \"character varying\", Type: &schema.StringType{T: \"character varying\"}}, Default: &schema.Literal{V: \"'logged_in'\"}},\n\t\t\t\t\t{Name: \"c8\", Type: &schema.ColumnType{Raw: \"cidr\", Type: &NetworkType{T: \"cidr\"}}},\n\t\t\t\t\t{Name: \"c9\", Type: &schema.ColumnType{Raw: \"circle\", Type: &schema.SpatialType{T: \"circle\"}}},\n\t\t\t\t\t{Name: \"c10\", Type: &schema.ColumnType{Raw: \"date\", Type: &schema.TimeType{T: \"date\"}}},\n\t\t\t\t\t{Name: \"c11\", Type: &schema.ColumnType{Raw: \"time with time zone\", Type: &schema.TimeType{T: \"time with time zone\", Precision: sqlx.P(0)}}},\n\t\t\t\t\t{Name: \"c12\", Type: &schema.ColumnType{Raw: \"double precision\", Type: &schema.FloatType{T: \"double precision\", Precision: 53}}},\n\t\t\t\t\t{Name: \"c13\", Type: &schema.ColumnType{Raw: \"real\", Type: &schema.FloatType{T: \"real\", Precision: 24}}, Default: &schema.RawExpr{X: \"random()\"}},\n\t\t\t\t\t{Name: \"c14\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}, Default: &schema.Literal{V: \"'{}'\"}},\n\t\t\t\t\t{Name: \"c15\", Type: &schema.ColumnType{Raw: \"jsonb\", Type: &schema.JSONType{T: \"jsonb\"}}, Default: &schema.Literal{V: \"'{}'\"}},\n\t\t\t\t\t{Name: \"c16\", Type: &schema.ColumnType{Raw: \"money\", Type: &CurrencyType{T: \"money\"}}},\n\t\t\t\t\t{Name: \"c17\", Type: &schema.ColumnType{Raw: \"numeric\", Type: &schema.DecimalType{T: \"numeric\"}}},\n\t\t\t\t\t{Name: \"c18\", Type: &schema.ColumnType{Raw: \"numeric\", Type: &schema.DecimalType{T: \"numeric\", Precision: 4, Scale: 4}}},\n\t\t\t\t\t{Name: \"c19\", Type: &schema.ColumnType{Raw: \"serial\", Type: &SerialType{T: \"serial\", SequenceName: \"t1_c19_seq\"}}},\n\t\t\t\t\t{Name: \"c20\", Type: &schema.ColumnType{Raw: \"uuid\", Type: &schema.UUIDType{T: \"uuid\"}}},\n\t\t\t\t\t{Name: \"c21\", Type: &schema.ColumnType{Raw: \"xml\", Type: &XMLType{T: \"xml\"}}},\n\t\t\t\t\t{Name: \"c22\", Type: &schema.ColumnType{Raw: \"ARRAY\", Null: true, Type: &ArrayType{Type: &schema.IntegerType{T: \"integer\"}, T: \"integer[]\"}}},\n\t\t\t\t\t{Name: \"c23\", Type: &schema.ColumnType{Raw: \"USER-DEFINED\", Null: true, Type: &UserDefinedType{T: \"ltree\", C: \"b\"}}},\n\t\t\t\t\t{Name: \"c24\", Type: &schema.ColumnType{Raw: \"state\", Type: stateE}},\n\t\t\t\t\t{Name: \"c25\", Type: &schema.ColumnType{Raw: \"timestamp without time zone\", Type: &schema.TimeType{T: \"timestamp without time zone\", Precision: sqlx.P(4)}}, Default: &schema.RawExpr{X: \"now()\"}},\n\t\t\t\t\t{Name: \"c26\", Type: &schema.ColumnType{Raw: \"timestamp with time zone\", Type: &schema.TimeType{T: \"timestamp with time zone\", Precision: sqlx.P(6)}}},\n\t\t\t\t\t{Name: \"c27\", Type: &schema.ColumnType{Raw: \"time without time zone\", Type: &schema.TimeType{T: \"time without time zone\", Precision: sqlx.P(6)}}},\n\t\t\t\t\t{Name: \"c28\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}, Attrs: []schema.Attr{&schema.GeneratedExpr{Expr: \"(c1 + c2)\"}}},\n\t\t\t\t\t{Name: \"c29\", Type: &schema.ColumnType{Raw: \"interval\", Type: &IntervalType{T: \"interval\", Precision: sqlx.P(6)}}},\n\t\t\t\t\t{Name: \"c30\", Type: &schema.ColumnType{Raw: \"interval\", Type: &IntervalType{T: \"interval\", F: \"MONTH\", Precision: sqlx.P(6)}}},\n\t\t\t\t\t{Name: \"c31\", Type: &schema.ColumnType{Raw: \"interval\", Type: &IntervalType{T: \"interval\", F: \"MINUTE TO SECOND\", Precision: sqlx.P(6)}}},\n\t\t\t\t\t{Name: \"c32\", Type: &schema.ColumnType{Raw: \"bigserial\", Type: &SerialType{T: \"bigserial\", SequenceName: \"t1_c32_seq\"}}},\n\t\t\t\t\t{Name: \"c33\", Type: &schema.ColumnType{Raw: `status`, Type: statusE}, Default: &schema.Literal{V: \"'unknown'\"}},\n\t\t\t\t\t{Name: \"c34\", Type: &schema.ColumnType{Raw: \"ARRAY\", Type: &ArrayType{T: \"state[]\", Type: stateE}}},\n\t\t\t\t\t{Name: \"c35\", Type: &schema.ColumnType{Raw: \"domain_char\", Type: &UserDefinedType{T: \"domain_char\", C: \"d\"}}},\n\t\t\t\t\t{Name: \"c36\", Type: &schema.ColumnType{Raw: \"tsvector\", Type: &TextSearchType{T: \"tsvector\"}}},\n\t\t\t\t\t{Name: \"c37\", Type: &schema.ColumnType{Raw: \"tsquery\", Type: &TextSearchType{T: \"tsquery\"}}},\n\t\t\t\t\t{Name: \"c38\", Type: &schema.ColumnType{Raw: \"datemultirange\", Type: &RangeType{T: \"datemultirange\"}}},\n\t\t\t\t\t{Name: \"c39\", Type: &schema.ColumnType{Raw: \"numrange\", Type: &RangeType{T: \"numrange\"}}},\n\t\t\t\t\t{Name: \"c40\", Type: &schema.ColumnType{Raw: \"smallserial\", Type: &SerialType{T: \"smallserial\", SequenceName: \"Users_c40_seq\"}}},\n\t\t\t\t\t{Name: \"c41\", Type: &schema.ColumnType{Raw: \"smallserial\", Type: &SerialType{T: \"smallserial\", SequenceName: \"T_C40_seq\"}}},\n\t\t\t\t\t{Name: \"c42\", Type: &schema.ColumnType{Raw: \"smallserial\", Type: &SerialType{T: \"smallserial\", SequenceName: \"T_C40_seq\"}}},\n\t\t\t\t}\n\t\t\t\tfor i, c := range expected {\n\t\t\t\t\trequire.Equal(c, t.Columns[i])\n\t\t\t\t}\n\t\t\t\trequire.Equal([]schema.Object{stateE, statusE}, t.Schema.Objects)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"table indexes\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.noEnums()\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\ntable_name | column_name |      data_type      | formatted |  is_nullable |         column_default          | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem |  oid  |  attnum  \n-----------+-------------+---------------------+-----------+--------------+---------------------------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+-------+-------\nusers      | id          | bigint              | int8      |  NO          |                                 |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    20 | \nusers      | c1          | smallint            | int2      |  NO          |                                 |                          |                16 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    21 | \nusers      | parent_id   | bigint              | int8      |  YES         |                                 |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    22 | \nusers      | ts          | tsvector            | tsvector  |  NO          |                                 |                          |                   |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |    23 | \n`))\n\t\t\t\tm.ExpectQuery(queryIndexes).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n   table_name   |    index_name   | index_type  | column_name | included | primary | unique | opexpr |   constraints   | predicate             |   expression              | desc | nulls_first | nulls_last | comment   |                 options               |   opclass_name    |   opclass_schema  | opclass_default | opclass_params | indnullsnotdistinct \n----------------+-----------------+-------------+-------------+----------+---------+--------+--------+-----------------+-----------------------+---------------------------+------+-------------+------------+-----------+---------------------------------------+-------------------+-------------------+-----------------+----------------+---------------------\nusers           | idx             | hash        |             | f        | f       | f      |        |                 |                       | \"left\"((c11)::text, 100)  | t    | t           | f          | boring    |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | idx1            | btree       |             | f        | f       | f      |        |                 | (id <> NULL::integer) | \"left\"((c11)::text, 100)  | t    | t           | f          |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | t1_c1_key       | btree       | c1          | f        | f       | t      |        | {\"name\": \"u\"}   |                       | c1                        | t    | t           | f          |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | t1_pkey         | btree       | id          | f        | t       | t      |        | {\"t_pkey\": \"p\"} |                       | id                        | t    | f           | f          |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | idx4            | btree       | c1          | f        | f       | t      |        |                 |                       | c1                        | f    | f           | f          |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | idx4            | btree       | id          | f        | f       | t      |        |                 |                       | id                        | f    | f           | t          |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | idx5            | btree       | c1          | f        | f       | t      |        |                 |                       | c1                        | f    | f           | f          |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | idx5            | btree       |             | f        | f       | t      |        |                 |                       | coalesce(parent_id, 0)    | f    | f           | f          |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | idx6            | brin        | c1          | f        | f       | t      |        |                 |                       |                           | f    | f           | f          |           | {autosummarize=true,pages_per_range=2}|     int4_ops      |     public        |        t        |                | f\nusers           | idx2            | btree       |             | f        | f       | f      |        |                 |                       | ((c * 2))                 | f    | f           | t          |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | idx2            | btree       | c1          | f        | f       | f      |        |                 |                       | c                         | f    | f           | t          |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | idx2            | btree       | id          | f        | f       | f      |        |                 |                       | d                         | f    | f           | t          |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | idx2            | btree       | c1          | t        | f       | f      |        |                 |                       | c                         |      |             |            |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | idx2            | btree       | parent_id   | t        | f       | f      |        |                 |                       | d                         |      |             |            |           |                                       |     int4_ops      |     public        |        t        |                | f\nusers           | dep_other_ns    | vec         | c1          | f        | f       | f      |        |                 |                       | c1                        |      |             |            |           |                                       |     vec_ops       |     unknown_ns    |        f        | {siglen=1}     | f\nusers           | tsx             | gist        | ts          | f        | f       | f      |        |                 |                       | ts                        |      |             |            |           |                                       |     tsvector_ops  |     pg_catalog    |        f        | {siglen=1}     | f\n`))\n\t\t\t\tm.noFKs()\n\t\t\t\tm.noChecks()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\tcolumns := []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"smallint\", Type: &schema.IntegerType{T: \"smallint\"}}},\n\t\t\t\t\t{Name: \"parent_id\", Type: &schema.ColumnType{Raw: \"bigint\", Null: true, Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t{Name: \"ts\", Type: &schema.ColumnType{Raw: \"tsvector\", Type: &TextSearchType{T: \"tsvector\"}}},\n\t\t\t\t}\n\t\t\t\tindexes := []*schema.Index{\n\t\t\t\t\t{Name: \"idx\", Table: t, Attrs: []schema.Attr{&IndexType{T: \"hash\"}, &schema.Comment{Text: \"boring\"}}, Parts: []*schema.IndexPart{{SeqNo: 1, X: &schema.RawExpr{X: `\"left\"((c11)::text, 100)`}, Desc: true, Attrs: []schema.Attr{&IndexColumnProperty{NullsFirst: true}}}}},\n\t\t\t\t\t{Name: \"idx1\", Table: t, Attrs: []schema.Attr{&IndexType{T: \"btree\"}, &IndexPredicate{P: `(id <> NULL::integer)`}}, Parts: []*schema.IndexPart{{SeqNo: 1, X: &schema.RawExpr{X: `\"left\"((c11)::text, 100)`}, Desc: true, Attrs: []schema.Attr{&IndexColumnProperty{NullsFirst: true}}}}},\n\t\t\t\t\t{Name: \"t1_c1_key\", Unique: true, Table: t, Attrs: []schema.Attr{&IndexType{T: \"btree\"}, &Constraint{N: \"name\", T: \"u\"}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[1], Desc: true, Attrs: []schema.Attr{&IndexColumnProperty{NullsFirst: true}}}}},\n\t\t\t\t\t{Name: \"idx4\", Unique: true, Table: t, Attrs: []schema.Attr{&IndexType{T: \"btree\"}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[1]}, {SeqNo: 2, C: columns[0], Attrs: []schema.Attr{&IndexColumnProperty{NullsLast: true}}}}},\n\t\t\t\t\t{Name: \"idx5\", Unique: true, Table: t, Attrs: []schema.Attr{&IndexType{T: \"btree\"}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[1]}, {SeqNo: 2, X: &schema.RawExpr{X: `coalesce(parent_id, 0)`}}}},\n\t\t\t\t\t{Name: \"idx6\", Unique: true, Table: t, Attrs: []schema.Attr{&IndexType{T: \"brin\"}, &IndexStorageParams{AutoSummarize: true, PagesPerRange: 2}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[1]}}},\n\t\t\t\t\t{Name: \"idx2\", Unique: false, Table: t, Attrs: []schema.Attr{&IndexType{T: \"btree\"}, &IndexInclude{Columns: columns[1:3]}}, Parts: []*schema.IndexPart{{SeqNo: 1, X: &schema.RawExpr{X: `((c * 2))`}, Attrs: []schema.Attr{&IndexColumnProperty{NullsLast: true}}}, {SeqNo: 2, C: columns[1], Attrs: []schema.Attr{&IndexColumnProperty{NullsLast: true}}}, {SeqNo: 3, C: columns[0], Attrs: []schema.Attr{&IndexColumnProperty{NullsLast: true}}}}},\n\t\t\t\t\t{Name: \"dep_other_ns\", Unique: false, Table: t, Attrs: []schema.Attr{&IndexType{T: \"vec\"}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[1], Attrs: []schema.Attr{&IndexOpClass{Name: \"unknown_ns.vec_ops\", Params: []struct{ N, V string }{{N: \"siglen\", V: \"1\"}}}}}}},\n\t\t\t\t\t{Name: \"tsx\", Unique: false, Table: t, Attrs: []schema.Attr{&IndexType{T: \"gist\"}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[3], Attrs: []schema.Attr{&IndexOpClass{Name: \"tsvector_ops\", Params: []struct{ N, V string }{{N: \"siglen\", V: \"1\"}}}}}}},\n\t\t\t\t}\n\t\t\t\tpk := &schema.Index{\n\t\t\t\t\tName:   \"t1_pkey\",\n\t\t\t\t\tUnique: true,\n\t\t\t\t\tTable:  t,\n\t\t\t\t\tAttrs:  []schema.Attr{&IndexType{T: \"btree\"}, &Constraint{N: \"t_pkey\", T: \"p\"}},\n\t\t\t\t\tParts:  []*schema.IndexPart{{SeqNo: 1, C: columns[0], Desc: true}},\n\t\t\t\t}\n\t\t\t\tcolumns[0].Indexes = append(columns[0].Indexes, pk, indexes[3], indexes[6])\n\t\t\t\tcolumns[1].Indexes = indexes[2:8]\n\t\t\t\tcolumns[3].Indexes = indexes[8:]\n\t\t\t\trequire.EqualValues(columns, t.Columns)\n\t\t\t\trequire.EqualValues(indexes, t.Indexes)\n\t\t\t\trequire.EqualValues(pk, t.PrimaryKey)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"fks\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.noEnums()\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\ntable_name | column_name |      data_type      | formatted | is_nullable |         column_default          | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem | oid  | attnum \n-----------+-------------+---------------------+-----------+-------------+---------------------------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+------+-----\nusers      | id          | integer             | int       | NO          |                                 |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   20 |   \nusers      | oid         | integer             | int       | NO          |                                 |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   21 |   \nusers      | uid         | integer             | int       | NO          |                                 |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   21 |   \n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.ExpectQuery(queryFKs).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\nconstraint_name | table_name | column_name | table_schema | referenced_table_name | referenced_column_name | referenced_schema_name | confupdtype | condeltype\n-----------------+------------+-------------+--------------+-----------------------+------------------------+------------------------+-------------+-------------\nmulti_column    | users      | id          | public       | t1                    | gid                    | public                 | a            | c\nmulti_column    | users      | id          | public       | t1                    | xid                    | public                 | a            | c\nmulti_column    | users      | oid         | public       | t1                    | gid                    | public                 | a            | c\nmulti_column    | users      | oid         | public       | t1                    | xid                    | public                 | a            | c\nself_reference  | users      | uid         | public       | users                 | id                     | public                 | a            | c\n`))\n\t\t\t\tm.noChecks()\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.Equal(\"public\", t.Schema.Name)\n\t\t\t\tfks := []*schema.ForeignKey{\n\t\t\t\t\t{Symbol: \"multi_column\", Table: t, OnUpdate: schema.NoAction, OnDelete: schema.Cascade, RefTable: &schema.Table{Name: \"t1\", Schema: t.Schema}, RefColumns: []*schema.Column{{Name: \"gid\"}, {Name: \"xid\"}}},\n\t\t\t\t\t{Symbol: \"self_reference\", Table: t, OnUpdate: schema.NoAction, OnDelete: schema.Cascade, RefTable: t},\n\t\t\t\t}\n\t\t\t\tcolumns := []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"integer\", Type: &schema.IntegerType{T: \"integer\"}}, ForeignKeys: fks[0:1]},\n\t\t\t\t\t{Name: \"oid\", Type: &schema.ColumnType{Raw: \"integer\", Type: &schema.IntegerType{T: \"integer\"}}, ForeignKeys: fks[0:1]},\n\t\t\t\t\t{Name: \"uid\", Type: &schema.ColumnType{Raw: \"integer\", Type: &schema.IntegerType{T: \"integer\"}}, ForeignKeys: fks[1:2]},\n\t\t\t\t}\n\t\t\t\tfks[0].Columns = columns[:2]\n\t\t\t\tfks[1].Columns = columns[2:]\n\t\t\t\tfks[1].RefColumns = columns[:1]\n\t\t\t\trequire.EqualValues(columns, t.Columns)\n\t\t\t\trequire.EqualValues(fks, t.ForeignKeys)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"check\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.noEnums()\n\t\t\t\tm.tableExists(\"public\", \"users\", true)\n\t\t\t\tm.ExpectQuery(queryColumns).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\ntable_name |column_name | data_type | formatted | is_nullable | column_default | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem | oid | attnum \n-----------+------------+-----------+-----------+-------------+----------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+-----+-----\nusers      | c1         | integer   | int4      | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  23 | \nusers      | c2         | integer   | int4      | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  23 | \nusers      | c3         | integer   | int4      | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |  23 | \n`))\n\t\t\t\tm.noIndexes()\n\t\t\t\tm.noFKs()\n\t\t\t\tm.ExpectQuery(queryChecks).\n\t\t\t\t\tWithArgs(\"public\", \"users\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\ntable_name   | constraint_name    |       expression        | column_name | column_indexes | no_inherit\n-------------+--------------------+-------------------------+-------------+----------------+----------------\nusers        | boring             | (c1 > 1)                | c1          | {1}            | t\nusers        | users_c2_check     | (c2 > 0)                | c2          | {2}            | f\nusers        | users_c2_check1    | (c2 > 0)                | c2          | {2}            | f\nusers        | users_check        | ((c2 + c1) > 2)         | c2          | {2,1}          | f\nusers        | users_check        | ((c2 + c1) > 2)         | c1          | {2,1}          | f\nusers        | users_check1       | (((c2 + c1) + c3) > 10) | c2          | {2,1,3}        | f\nusers        | users_check1       | (((c2 + c1) + c3) > 10) | c1          | {2,1,3}        | f\nusers        | users_check1       | (((c2 + c1) + c3) > 10) | c3          | {2,1,3}        | f\n`))\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Equal(\"users\", t.Name)\n\t\t\t\trequire.Equal(\"public\", t.Schema.Name)\n\t\t\t\tchecks := []schema.Attr{\n\t\t\t\t\t&schema.Check{Name: \"boring\", Expr: \"(c1 > 1)\", Attrs: []schema.Attr{&CheckColumns{Columns: []string{\"c1\"}}, &NoInherit{}}},\n\t\t\t\t\t&schema.Check{Name: \"users_c2_check\", Expr: \"(c2 > 0)\", Attrs: []schema.Attr{&CheckColumns{Columns: []string{\"c2\"}}}},\n\t\t\t\t\t&schema.Check{Name: \"users_c2_check1\", Expr: \"(c2 > 0)\", Attrs: []schema.Attr{&CheckColumns{Columns: []string{\"c2\"}}}},\n\t\t\t\t\t&schema.Check{Name: \"users_check\", Expr: \"((c2 + c1) > 2)\", Attrs: []schema.Attr{&CheckColumns{Columns: []string{\"c2\", \"c1\"}}}},\n\t\t\t\t\t&schema.Check{Name: \"users_check1\", Expr: \"(((c2 + c1) + c3) > 10)\", Attrs: []schema.Attr{&CheckColumns{Columns: []string{\"c2\", \"c1\", \"c3\"}}}},\n\t\t\t\t}\n\t\t\t\trequire.EqualValues([]*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"integer\", Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{checks[0], checks[3], checks[4]}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"integer\", Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{checks[1], checks[2], checks[3], checks[4]}},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"integer\", Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{checks[4]}},\n\t\t\t\t}, t.Columns)\n\t\t\t\trequire.EqualValues(checks, t.Attrs)\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdb, m, err := sqlmock.New()\n\t\t\trequire.NoError(t, err)\n\t\t\tmk := mock{m}\n\t\t\tmk.version(\"150000\")\n\t\t\tvar drv migrate.Driver\n\t\t\tdrv, err = Open(db)\n\t\t\trequire.NoError(t, err)\n\t\t\tdrv.(*Driver).schema = \"public\"\n\t\t\tmk.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, \"= $1\"))).\n\t\t\t\tWithArgs(\"public\").\n\t\t\t\tWillReturnRows(sqltest.Rows(`\n schema_name | comment \n-------------+---------\n public      | nil\n`))\n\t\t\ttt.before(mk)\n\t\t\ts, err := drv.InspectSchema(context.Background(), \"public\", &schema.InspectOptions{\n\t\t\t\tMode: schema.InspectSchemas | schema.InspectTables | schema.InspectTypes,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\ttt.expect(require.New(t), s.Tables[0], err)\n\t\t})\n\t}\n}\n\nfunc TestDriver_InspectPartitionedTable(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmk := mock{m}\n\tmk.version(\"150000\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\tmk.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, \"= CURRENT_SCHEMA()\"))).\n\t\tWillReturnRows(sqltest.Rows(`\n schema_name | comment \n-------------+---------\n public      | nil\n`))\n\tmk.noEnums()\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, \"$1\"))).\n\t\tWithArgs(\"public\").\n\t\tWillReturnRows(sqltest.Rows(`\n oid   | table_schema | table_name  | comment | partition_attrs | partition_strategy |                  partition_exprs                   |                  extra                   \n-------+--------------+-------------+---------+-----------------+--------------------+----------------------------------------------------+----------------------------------------------------\n 112  | public       | logs1       |         |                 |                     |                                                    |                                                    \n 113  | public       | logs2       |         | 1               | r                   |                                                    |                                                    \n 114  | public       | logs3       |         | 2 0 0           | l                   | (a + b), (a + (b * 2))                             |                              \n\n`))\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(columnsQuery, \"$2, $3, $4\"))).\n\t\tWithArgs(\"public\", \"logs1\", \"logs2\", \"logs3\").\n\t\tWillReturnRows(sqltest.Rows(`\ntable_name |column_name | data_type | formatted | is_nullable | column_default | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  | identity_generation | generation_expression | comment | typtype | typelem |  oid |  attnum \n-----------+------------+-----------+-----------+-------------+----------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------+-------------+----------------+--------------------+------------------+---------------------+-----------------------+---------+---------+---------+------+--------\nlogs1      | c1         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   23 |  \nlogs2      | c2         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   23 |  \nlogs2      | c3         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   23 |  \nlogs3      | c4         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   23 |  \nlogs3      | c5         | integer   | integer   | NO          |                |                          |                32 |                    |             0 |               |                    |                | NO          |                |                    |                  |                     |                       |         | b       |         |   23 |  \n`))\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexesAbove15, \"$2, $3, $4\"))).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_name\", \"index_name\", \"column_name\", \"primary\", \"unique\", \"constraint_type\", \"predicate\", \"expression\", \"options\", \"indnullsnotdistinct\"}))\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(fksQuery, \"$2, $3, $4\"))).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"constraint_name\", \"table_name\", \"column_name\", \"referenced_table_name\", \"referenced_column_name\", \"referenced_table_schema\", \"update_rule\", \"delete_rule\"}))\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(checksQuery, \"$2, $3, $4\"))).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_name\", \"constraint_name\", \"expression\", \"column_name\", \"column_indexes\"}))\n\ts, err := drv.InspectSchema(context.Background(), \"\", &schema.InspectOptions{\n\t\tMode: schema.InspectSchemas | schema.InspectTables | schema.InspectTypes,\n\t})\n\trequire.NoError(t, err)\n\n\tt1, ok := s.Table(\"logs1\")\n\trequire.True(t, ok)\n\trequire.Equal(t, []schema.Attr{&OID{V: 112}}, t1.Attrs)\n\n\tt2, ok := s.Table(\"logs2\")\n\trequire.True(t, ok)\n\trequire.Len(t, t2.Attrs, 2)\n\tkey := t2.Attrs[1].(*Partition)\n\trequire.Equal(t, PartitionTypeRange, key.T)\n\trequire.Equal(t, []*PartitionPart{\n\t\t{C: &schema.Column{Name: \"c2\", Type: &schema.ColumnType{Raw: \"integer\", Type: &schema.IntegerType{T: \"integer\"}}}},\n\t}, key.Parts)\n\n\tt3, ok := s.Table(\"logs3\")\n\trequire.True(t, ok)\n\trequire.Len(t, t3.Attrs, 2)\n\tkey = t3.Attrs[1].(*Partition)\n\trequire.Equal(t, PartitionTypeList, key.T)\n\trequire.Equal(t, []*PartitionPart{\n\t\t{C: &schema.Column{Name: \"c5\", Type: &schema.ColumnType{Raw: \"integer\", Type: &schema.IntegerType{T: \"integer\"}}}},\n\t\t{X: &schema.RawExpr{X: \"(a + b)\"}},\n\t\t{X: &schema.RawExpr{X: \"(a + (b * 2))\"}},\n\t}, key.Parts)\n}\n\nfunc TestDriver_InspectCRDBSchema(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmk := mock{m}\n\tmk.ExpectQuery(sqltest.Escape(paramsQuery)).\n\t\tWillReturnRows(sqltest.Rows(`\n  version       |  am  | crdb\n----------------|------|-----\n 130000         | heap | cockroach\n`))\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\tmk.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, \"= $1\"))).\n\t\tWithArgs(\"public\").\n\t\tWillReturnRows(sqltest.Rows(`\n schema_name | comment \n-------------+---------\n public      | nil\n`))\n\tmk.tableExists(\"public\", \"users\", true)\n\tmk.ExpectQuery(queryCRDBColumns).\n\t\tWithArgs(\"public\", \"users\").\n\t\tWillReturnRows(sqltest.Rows(`\ntable_name  | column_name | data_type | formatted | is_nullable |              column_default               | character_maximum_length | numeric_precision | datetime_precision | numeric_scale | interval_type | character_set_name | collation_name | is_identity | identity_start | identity_increment |   identity_last  |  identity_generation  | generation_expression | comment | typtype | typelem | oid | attnum \n------------+-------------+-----------+-----------+-------------+-------------------------------------------+--------------------------+-------------------+--------------------+---------------+---------------+--------------------+----------------|-------------+----------------+--------------------+------------------+-----------------------+-----------------------+---------+---------+---------+-----+--------\nusers       | a           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         | 20  |        \nusers       | b           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         | 20  |        \nusers       | c           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         | 20  |        \nusers       | d           | bigint    | bigint    | NO          |                                           |                          |                64 |                    |             0 |               |                    |                | NO          |                |                    |                  |                       |                       |         | b       |         | 20  |        \n`))\n\tmk.ExpectQuery(queryCRDBIndexes).\n\t\tWithArgs(\"public\", \"users\").\n\t\tWillReturnRows(sqltest.Rows(`\ntable_name  | index_name | column_name | primary | unique | constraint_type |                                   create_stmt                                   | predicate | expression | comment \n------------+------------+-------------+---------+--------+-----------------+---------------------------------------------------------------------------------+-----------+------------+---------\nusers       | idx1       | a           | false   | false  |                 | CREATE INDEX idx1 ON defaultdb.public.serial USING btree (a ASC)                |           | a          |  \nusers       | idx2       | b           | false   | true   | u               | CREATE UNIQUE INDEX idx2 ON defaultdb.public.serial USING btree (b ASC)         |           | b          |  \nusers       | idx3       | c           | false   | false  |                 | CREATE INDEX idx3 ON defaultdb.public.serial USING btree (c DESC)               |           | c          | boring \nusers       | idx4       | d           | false   | false  |                 | CREATE INDEX idx5 ON defaultdb.public.serial USING btree (d ASC) WHERE (d < 10) | d < 10    | d          |  \nusers       | idx5       | a           | false   | false  |                 | CREATE INDEX idx5 ON defaultdb.public.serial USING btree (a ASC, b ASC, c ASC)  |           | a          |  \nusers       | idx5       | b           | false   | false  |                 | CREATE INDEX idx5 ON defaultdb.public.serial USING btree (a ASC, b ASC, c ASC)  |           | b          |  \nusers       | idx5       | c           | false   | false  |                 | CREATE INDEX idx5 ON defaultdb.public.serial USING btree (a ASC, b ASC, c ASC)  |           | c          |  \n`))\n\tmk.noFKs()\n\tmk.noChecks()\n\ts, err := drv.InspectSchema(context.Background(), \"public\", &schema.InspectOptions{\n\t\tMode: schema.InspectSchemas | schema.InspectTables,\n\t})\n\trequire.NoError(t, err)\n\ttbl := s.Tables[0]\n\trequire.Equal(t, \"users\", tbl.Name)\n\tcolumns := []*schema.Column{\n\t\t{Name: \"a\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t{Name: \"b\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t{Name: \"c\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t{Name: \"d\", Type: &schema.ColumnType{Raw: \"bigint\", Type: &schema.IntegerType{T: \"bigint\"}}},\n\t}\n\tindexes := []*schema.Index{\n\t\t{Name: \"idx1\", Table: tbl, Attrs: []schema.Attr{&IndexType{T: \"btree\"}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[0]}}},\n\t\t{Name: \"idx2\", Unique: true, Table: tbl, Attrs: []schema.Attr{&IndexType{T: \"btree\"}, &Constraint{T: \"u\"}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[1]}}},\n\t\t{Name: \"idx3\", Table: tbl, Attrs: []schema.Attr{&IndexType{T: \"btree\"}, &schema.Comment{Text: \"boring\"}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[2], Desc: true}}},\n\t\t{Name: \"idx4\", Table: tbl, Attrs: []schema.Attr{&IndexType{T: \"btree\"}, &IndexPredicate{P: `d < 10`}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[3]}}},\n\t\t{Name: \"idx5\", Table: tbl, Attrs: []schema.Attr{&IndexType{T: \"btree\"}}, Parts: []*schema.IndexPart{{SeqNo: 1, C: columns[0]}, {SeqNo: 2, C: columns[1]}, {SeqNo: 3, C: columns[2]}}},\n\t}\n\tcolumns[0].Indexes = []*schema.Index{indexes[0], indexes[4]}\n\tcolumns[1].Indexes = []*schema.Index{indexes[1], indexes[4]}\n\tcolumns[2].Indexes = []*schema.Index{indexes[2], indexes[4]}\n\tcolumns[3].Indexes = []*schema.Index{indexes[3]}\n\trequire.EqualValues(t, columns, tbl.Columns)\n\trequire.EqualValues(t, indexes, tbl.Indexes)\n}\n\nfunc TestDriver_InspectSchema(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmk := mock{m}\n\tmk.version(\"130000\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\tmk.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, \"= CURRENT_SCHEMA()\"))).\n\t\tWillReturnRows(sqltest.Rows(`\n schema_name | comment \n-------------+---------\n test        | boring\n`))\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, \"$1\"))).\n\t\tWithArgs(\"test\").\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_schema\", \"table_name\", \"comment\", \"partition_attrs\", \"partition_strategy\", \"partition_exprs\"}))\n\ts, err := drv.InspectSchema(context.Background(), \"\", &schema.InspectOptions{\n\t\tMode: schema.InspectSchemas | schema.InspectTables,\n\t})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, func() *schema.Schema {\n\t\tr := &schema.Realm{\n\t\t\tSchemas: []*schema.Schema{\n\t\t\t\tschema.New(\"test\").SetComment(\"boring\"),\n\t\t\t},\n\t\t}\n\t\tr.Schemas[0].Realm = r\n\t\treturn r.Schemas[0]\n\t}(), s)\n}\n\nfunc TestDriver_Realm(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmk := mock{m}\n\tmk.version(\"130000\")\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\t// Set search_path to ''.\n\tmk.ExpectQuery(sqltest.Escape(\"SELECT current_setting('search_path'), set_config('search_path', '', false)\")).\n\t\tWillReturnRows(sqltest.Rows(`\n current_setting | set_config\n-----------------+------------\n       public    |\n`))\n\tmk.ExpectQuery(sqltest.Escape(schemasQuery)).\n\t\tWillReturnRows(sqltest.Rows(`\n schema_name | comment \n-------------+---------\n test        | nil\n public      | nil\n`))\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, \"$1, $2\"))).\n\t\tWithArgs(\"test\", \"public\").\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_schema\", \"table_name\", \"comment\", \"partition_attrs\", \"partition_strategy\", \"partition_exprs\"}))\n\t// Reset search_path to 'public'.\n\tmk.ExpectQuery(sqltest.Escape(\"SELECT set_config('search_path', $1, false)\")).\n\t\tWithArgs(\"public\").\n\t\tWillReturnRows(sqlmock.NewRows(nil))\n\trealm, err := drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\tMode: schema.InspectSchemas | schema.InspectTables,\n\t})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, func() *schema.Realm {\n\t\tr := &schema.Realm{\n\t\t\tSchemas: []*schema.Schema{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"public\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tr.Schemas[0].Realm = r\n\t\tr.Schemas[1].Realm = r\n\t\treturn r\n\t}(), realm)\n\n\t// No need to reset, if the search_path was not set.\n\tmk.ExpectQuery(sqltest.Escape(\"SELECT current_setting('search_path'), set_config('search_path', '', false)\")).\n\t\tWillReturnRows(sqltest.Rows(`\n current_setting | set_config\n-----------------+------------\n                 |\n`))\n\tmk.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, \"IN ($1, $2)\"))).\n\t\tWithArgs(\"test\", \"public\").\n\t\tWillReturnRows(sqltest.Rows(`\n schema_name | comment \n-------------+---------\n test        | nil\n public      | nil\n`))\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, \"$1, $2\"))).\n\t\tWithArgs(\"test\", \"public\").\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_schema\", \"table_name\", \"comment\", \"partition_attrs\", \"partition_strategy\", \"partition_exprs\"}))\n\trealm, err = drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\tSchemas: []string{\"test\", \"public\"},\n\t\tMode:    schema.InspectSchemas | schema.InspectTables,\n\t})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, func() *schema.Realm {\n\t\tr := &schema.Realm{\n\t\t\tSchemas: []*schema.Schema{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"public\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tr.Schemas[0].Realm = r\n\t\tr.Schemas[1].Realm = r\n\t\treturn r\n\t}(), realm)\n\n\t// No need to reset, if the search_path was not set.\n\tmk.ExpectQuery(sqltest.Escape(\"SELECT current_setting('search_path'), set_config('search_path', '', false)\")).\n\t\tWillReturnRows(sqltest.Rows(`\n current_setting | set_config\n-----------------+------------\n                 |\n`))\n\tmk.ExpectQuery(sqltest.Escape(fmt.Sprintf(schemasQueryArgs, \"= $1\"))).\n\t\tWithArgs(\"test\").\n\t\tWillReturnRows(sqltest.Rows(`\n schema_name | comment \n-------------+---------\n test        | nil\n`))\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(tablesQuery, \"$1\"))).\n\t\tWithArgs(\"test\").\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_schema\", \"table_name\", \"comment\", \"partition_attrs\", \"partition_strategy\", \"partition_exprs\"}))\n\trealm, err = drv.InspectRealm(context.Background(), &schema.InspectRealmOption{\n\t\tSchemas: []string{\"test\"},\n\t\tMode:    schema.InspectSchemas | schema.InspectTables,\n\t})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, func() *schema.Realm {\n\t\tr := &schema.Realm{\n\t\t\tSchemas: []*schema.Schema{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tr.Schemas[0].Realm = r\n\t\treturn r\n\t}(), realm)\n}\n\nfunc TestInspectMode_InspectRealm(t *testing.T) {\n\tdb, m, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tmk := mock{m}\n\tmk.version(\"130000\")\n\tmk.ExpectQuery(sqltest.Escape(\"SELECT current_setting('search_path'), set_config('search_path', '', false)\")).\n\t\tWillReturnRows(sqltest.Rows(`\n current_setting | set_config\n-----------------+------------\n                 |\n`))\n\tmk.ExpectQuery(sqltest.Escape(schemasQuery)).\n\t\tWillReturnRows(sqltest.Rows(`\n schema_name | comment \n-------------+---------\n test        | nil\n public      | nil\n`))\n\tdrv, err := Open(db)\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(enumsQuery, \"$1, $2\"))).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"schema_name\", \"enum_name\", \"comment\", \"enum_type\", \"enum_value\"}))\n\trealm, err := drv.InspectRealm(context.Background(), &schema.InspectRealmOption{Mode: schema.InspectSchemas})\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, func() *schema.Realm {\n\t\tr := &schema.Realm{\n\t\t\tSchemas: []*schema.Schema{\n\t\t\t\t{\n\t\t\t\t\tName: \"test\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"public\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tr.Schemas[0].Realm = r\n\t\tr.Schemas[1].Realm = r\n\t\treturn r\n\t}(), realm)\n}\n\nfunc TestIndexOpClass_UnmarshalText(t *testing.T) {\n\tvar op IndexOpClass\n\trequire.NoError(t, op.UnmarshalText([]byte(\"int4_ops\")))\n\trequire.EqualValues(t, IndexOpClass{Name: \"int4_ops\"}, op)\n\n\top = IndexOpClass{}\n\trequire.NoError(t, op.UnmarshalText([]byte(\"\")))\n\trequire.EqualValues(t, IndexOpClass{}, op)\n\n\trequire.NoError(t, op.UnmarshalText([]byte(\"int4_ops(siglen=1)\")))\n\trequire.EqualValues(t, IndexOpClass{Name: \"int4_ops\", Params: []struct{ N, V string }{{\"siglen\", \"1\"}}}, op)\n}\n\ntype mock struct {\n\tsqlmock.Sqlmock\n}\n\nfunc (m mock) version(version string) {\n\tm.ExpectQuery(sqltest.Escape(paramsQuery)).\n\t\tWillReturnRows(sqltest.Rows(`\n  setting       |  am  | crdb\n----------------|------|-----\n ` + version + `| heap | NULL\n`))\n}\n\nfunc (m mock) tableExists(schema, table string, exists bool) {\n\trows := sqlmock.NewRows([]string{\"oid\", \"table_schema\", \"table_name\", \"table_comment\", \"partition_attrs\", \"partition_strategy\", \"partition_exprs\", \"row_security\"})\n\tif exists {\n\t\trows.AddRow(nil, schema, table, nil, nil, nil, nil, nil)\n\t}\n\tm.ExpectQuery(queryTables).\n\t\tWithArgs(schema).\n\t\tWillReturnRows(rows)\n}\n\nfunc (m mock) noIndexes() {\n\tm.ExpectQuery(queryIndexes).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_name\", \"index_name\", \"column_name\", \"primary\", \"unique\", \"constraint_type\", \"predicate\", \"expression\", \"options\", \"indnullsnotdistinct\"}))\n}\n\nfunc (m mock) noFKs() {\n\tm.ExpectQuery(queryFKs).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"constraint_name\", \"table_name\", \"column_name\", \"referenced_table_name\", \"referenced_column_name\", \"referenced_table_schema\", \"update_rule\", \"delete_rule\"}))\n}\n\nfunc (m mock) noChecks() {\n\tm.ExpectQuery(queryChecks).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"table_name\", \"constraint_name\", \"expression\", \"column_name\", \"column_indexes\"}))\n}\n\nfunc (m mock) noEnums() {\n\tm.ExpectQuery(queryEnums).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"schema_name\", \"enum_name\", \"comment\", \"enum_type\", \"enum_value\"}))\n}\n"
  },
  {
    "path": "sql/postgres/internal/postgresop/postgresop.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage postgresop\n\nimport \"sync\"\n\n// Class describes an index operator class.\ntype Class struct {\n\tName    string // operator class name\n\tMethod  string // index method\n\tType    string // indexed data type\n\tDefault bool   // default to the type/method above\n}\n\n// Classes defined in latest PostgreSQL version (15).\nvar Classes = []*Class{\n\t{Name: \"bit_minmax_ops\", Method: \"BRIN\", Type: \"bit\", Default: true},\n\t{Name: \"box_inclusion_ops\", Method: \"BRIN\", Type: \"box\", Default: true},\n\t{Name: \"bpchar_bloom_ops\", Method: \"BRIN\", Type: \"character\", Default: false},\n\t{Name: \"bpchar_minmax_ops\", Method: \"BRIN\", Type: \"character\", Default: true},\n\t{Name: \"bytea_bloom_ops\", Method: \"BRIN\", Type: \"bytea\", Default: false},\n\t{Name: \"bytea_minmax_ops\", Method: \"BRIN\", Type: \"bytea\", Default: true},\n\t{Name: \"char_bloom_ops\", Method: \"BRIN\", Type: \"char\", Default: false},\n\t{Name: \"char_minmax_ops\", Method: \"BRIN\", Type: \"char\", Default: true},\n\t{Name: \"date_bloom_ops\", Method: \"BRIN\", Type: \"date\", Default: false},\n\t{Name: \"date_minmax_multi_ops\", Method: \"BRIN\", Type: \"date\", Default: false},\n\t{Name: \"date_minmax_ops\", Method: \"BRIN\", Type: \"date\", Default: true},\n\t{Name: \"float4_bloom_ops\", Method: \"BRIN\", Type: \"real\", Default: false},\n\t{Name: \"float4_minmax_multi_ops\", Method: \"BRIN\", Type: \"real\", Default: false},\n\t{Name: \"float4_minmax_ops\", Method: \"BRIN\", Type: \"real\", Default: true},\n\t{Name: \"float8_bloom_ops\", Method: \"BRIN\", Type: \"double precision\", Default: false},\n\t{Name: \"float8_minmax_multi_ops\", Method: \"BRIN\", Type: \"double precision\", Default: false},\n\t{Name: \"float8_minmax_ops\", Method: \"BRIN\", Type: \"double precision\", Default: true},\n\t{Name: \"inet_bloom_ops\", Method: \"BRIN\", Type: \"inet\", Default: false},\n\t{Name: \"inet_inclusion_ops\", Method: \"BRIN\", Type: \"inet\", Default: true},\n\t{Name: \"inet_minmax_multi_ops\", Method: \"BRIN\", Type: \"inet\", Default: false},\n\t{Name: \"inet_minmax_ops\", Method: \"BRIN\", Type: \"inet\", Default: false},\n\t{Name: \"int2_bloom_ops\", Method: \"BRIN\", Type: \"smallint\", Default: false},\n\t{Name: \"int2_minmax_multi_ops\", Method: \"BRIN\", Type: \"smallint\", Default: false},\n\t{Name: \"int2_minmax_ops\", Method: \"BRIN\", Type: \"smallint\", Default: true},\n\t{Name: \"int4_bloom_ops\", Method: \"BRIN\", Type: \"integer\", Default: false},\n\t{Name: \"int4_minmax_multi_ops\", Method: \"BRIN\", Type: \"integer\", Default: false},\n\t{Name: \"int4_minmax_ops\", Method: \"BRIN\", Type: \"integer\", Default: true},\n\t{Name: \"int8_bloom_ops\", Method: \"BRIN\", Type: \"bigint\", Default: false},\n\t{Name: \"int8_minmax_multi_ops\", Method: \"BRIN\", Type: \"bigint\", Default: false},\n\t{Name: \"int8_minmax_ops\", Method: \"BRIN\", Type: \"bigint\", Default: true},\n\t{Name: \"interval_bloom_ops\", Method: \"BRIN\", Type: \"interval\", Default: false},\n\t{Name: \"interval_minmax_multi_ops\", Method: \"BRIN\", Type: \"interval\", Default: false},\n\t{Name: \"interval_minmax_ops\", Method: \"BRIN\", Type: \"interval\", Default: true},\n\t{Name: \"macaddr8_bloom_ops\", Method: \"BRIN\", Type: \"macaddr8\", Default: false},\n\t{Name: \"macaddr8_minmax_multi_ops\", Method: \"BRIN\", Type: \"macaddr8\", Default: false},\n\t{Name: \"macaddr8_minmax_ops\", Method: \"BRIN\", Type: \"macaddr8\", Default: true},\n\t{Name: \"macaddr_bloom_ops\", Method: \"BRIN\", Type: \"macaddr\", Default: false},\n\t{Name: \"macaddr_minmax_multi_ops\", Method: \"BRIN\", Type: \"macaddr\", Default: false},\n\t{Name: \"macaddr_minmax_ops\", Method: \"BRIN\", Type: \"macaddr\", Default: true},\n\t{Name: \"name_bloom_ops\", Method: \"BRIN\", Type: \"name\", Default: false},\n\t{Name: \"name_minmax_ops\", Method: \"BRIN\", Type: \"name\", Default: true},\n\t{Name: \"numeric_bloom_ops\", Method: \"BRIN\", Type: \"numeric\", Default: false},\n\t{Name: \"numeric_minmax_multi_ops\", Method: \"BRIN\", Type: \"numeric\", Default: false},\n\t{Name: \"numeric_minmax_ops\", Method: \"BRIN\", Type: \"numeric\", Default: true},\n\t{Name: \"oid_bloom_ops\", Method: \"BRIN\", Type: \"oid\", Default: false},\n\t{Name: \"oid_minmax_multi_ops\", Method: \"BRIN\", Type: \"oid\", Default: false},\n\t{Name: \"oid_minmax_ops\", Method: \"BRIN\", Type: \"oid\", Default: true},\n\t{Name: \"pg_lsn_bloom_ops\", Method: \"BRIN\", Type: \"pg_lsn\", Default: false},\n\t{Name: \"pg_lsn_minmax_multi_ops\", Method: \"BRIN\", Type: \"pg_lsn\", Default: false},\n\t{Name: \"pg_lsn_minmax_ops\", Method: \"BRIN\", Type: \"pg_lsn\", Default: true},\n\t{Name: \"range_inclusion_ops\", Method: \"BRIN\", Type: \"anyrange\", Default: true},\n\t{Name: \"text_bloom_ops\", Method: \"BRIN\", Type: \"text\", Default: false},\n\t{Name: \"text_minmax_ops\", Method: \"BRIN\", Type: \"text\", Default: true},\n\t{Name: \"tid_bloom_ops\", Method: \"BRIN\", Type: \"tid\", Default: false},\n\t{Name: \"tid_minmax_multi_ops\", Method: \"BRIN\", Type: \"tid\", Default: false},\n\t{Name: \"tid_minmax_ops\", Method: \"BRIN\", Type: \"tid\", Default: true},\n\t{Name: \"time_bloom_ops\", Method: \"BRIN\", Type: \"time without time zone\", Default: false},\n\t{Name: \"time_minmax_multi_ops\", Method: \"BRIN\", Type: \"time without time zone\", Default: false},\n\t{Name: \"time_minmax_ops\", Method: \"BRIN\", Type: \"time without time zone\", Default: true},\n\t{Name: \"timestamp_bloom_ops\", Method: \"BRIN\", Type: \"timestamp without time zone\", Default: false},\n\t{Name: \"timestamp_minmax_multi_ops\", Method: \"BRIN\", Type: \"timestamp without time zone\", Default: false},\n\t{Name: \"timestamp_minmax_ops\", Method: \"BRIN\", Type: \"timestamp without time zone\", Default: true},\n\t{Name: \"timestamptz_bloom_ops\", Method: \"BRIN\", Type: \"timestamp with time zone\", Default: false},\n\t{Name: \"timestamptz_minmax_multi_ops\", Method: \"BRIN\", Type: \"timestamp with time zone\", Default: false},\n\t{Name: \"timestamptz_minmax_ops\", Method: \"BRIN\", Type: \"timestamp with time zone\", Default: true},\n\t{Name: \"timetz_bloom_ops\", Method: \"BRIN\", Type: \"time with time zone\", Default: false},\n\t{Name: \"timetz_minmax_multi_ops\", Method: \"BRIN\", Type: \"time with time zone\", Default: false},\n\t{Name: \"timetz_minmax_ops\", Method: \"BRIN\", Type: \"time with time zone\", Default: true},\n\t{Name: \"uuid_bloom_ops\", Method: \"BRIN\", Type: \"uuid\", Default: false},\n\t{Name: \"uuid_minmax_multi_ops\", Method: \"BRIN\", Type: \"uuid\", Default: false},\n\t{Name: \"uuid_minmax_ops\", Method: \"BRIN\", Type: \"uuid\", Default: true},\n\t{Name: \"varbit_minmax_ops\", Method: \"BRIN\", Type: \"bit varying\", Default: true},\n\t{Name: \"array_ops\", Method: \"BTREE\", Type: \"anyarray\", Default: true},\n\t{Name: \"bit_ops\", Method: \"BTREE\", Type: \"bit\", Default: true},\n\t{Name: \"bool_ops\", Method: \"BTREE\", Type: \"boolean\", Default: true},\n\t{Name: \"bpchar_ops\", Method: \"BTREE\", Type: \"character\", Default: true},\n\t{Name: \"bpchar_pattern_ops\", Method: \"BTREE\", Type: \"character\", Default: false},\n\t{Name: \"bytea_ops\", Method: \"BTREE\", Type: \"bytea\", Default: true},\n\t{Name: \"char_ops\", Method: \"BTREE\", Type: \"char\", Default: true},\n\t{Name: \"cidr_ops\", Method: \"BTREE\", Type: \"inet\", Default: false},\n\t{Name: \"date_ops\", Method: \"BTREE\", Type: \"date\", Default: true},\n\t{Name: \"enum_ops\", Method: \"BTREE\", Type: \"anyenum\", Default: true},\n\t{Name: \"float4_ops\", Method: \"BTREE\", Type: \"real\", Default: true},\n\t{Name: \"float8_ops\", Method: \"BTREE\", Type: \"double precision\", Default: true},\n\t{Name: \"inet_ops\", Method: \"BTREE\", Type: \"inet\", Default: true},\n\t{Name: \"int2_ops\", Method: \"BTREE\", Type: \"smallint\", Default: true},\n\t{Name: \"int4_ops\", Method: \"BTREE\", Type: \"integer\", Default: true},\n\t{Name: \"int8_ops\", Method: \"BTREE\", Type: \"bigint\", Default: true},\n\t{Name: \"interval_ops\", Method: \"BTREE\", Type: \"interval\", Default: true},\n\t{Name: \"jsonb_ops\", Method: \"BTREE\", Type: \"jsonb\", Default: true},\n\t{Name: \"macaddr8_ops\", Method: \"BTREE\", Type: \"macaddr8\", Default: true},\n\t{Name: \"macaddr_ops\", Method: \"BTREE\", Type: \"macaddr\", Default: true},\n\t{Name: \"money_ops\", Method: \"BTREE\", Type: \"money\", Default: true},\n\t{Name: \"multirange_ops\", Method: \"BTREE\", Type: \"anymultirange\", Default: true},\n\t{Name: \"name_ops\", Method: \"BTREE\", Type: \"name\", Default: true},\n\t{Name: \"numeric_ops\", Method: \"BTREE\", Type: \"numeric\", Default: true},\n\t{Name: \"oid_ops\", Method: \"BTREE\", Type: \"oid\", Default: true},\n\t{Name: \"oidvector_ops\", Method: \"BTREE\", Type: \"oidvector\", Default: true},\n\t{Name: \"pg_lsn_ops\", Method: \"BTREE\", Type: \"pg_lsn\", Default: true},\n\t{Name: \"range_ops\", Method: \"BTREE\", Type: \"anyrange\", Default: true},\n\t{Name: \"record_image_ops\", Method: \"BTREE\", Type: \"record\", Default: false},\n\t{Name: \"record_ops\", Method: \"BTREE\", Type: \"record\", Default: true},\n\t{Name: \"text_ops\", Method: \"BTREE\", Type: \"text\", Default: true},\n\t{Name: \"text_pattern_ops\", Method: \"BTREE\", Type: \"text\", Default: false},\n\t{Name: \"tid_ops\", Method: \"BTREE\", Type: \"tid\", Default: true},\n\t{Name: \"time_ops\", Method: \"BTREE\", Type: \"time without time zone\", Default: true},\n\t{Name: \"timestamp_ops\", Method: \"BTREE\", Type: \"timestamp without time zone\", Default: true},\n\t{Name: \"timestamptz_ops\", Method: \"BTREE\", Type: \"timestamp with time zone\", Default: true},\n\t{Name: \"timetz_ops\", Method: \"BTREE\", Type: \"time with time zone\", Default: true},\n\t{Name: \"tsquery_ops\", Method: \"BTREE\", Type: \"tsquery\", Default: true},\n\t{Name: \"tsvector_ops\", Method: \"BTREE\", Type: \"tsvector\", Default: true},\n\t{Name: \"uuid_ops\", Method: \"BTREE\", Type: \"uuid\", Default: true},\n\t{Name: \"varbit_ops\", Method: \"BTREE\", Type: \"bit varying\", Default: true},\n\t{Name: \"varchar_ops\", Method: \"BTREE\", Type: \"text\", Default: false},\n\t{Name: \"varchar_pattern_ops\", Method: \"BTREE\", Type: \"text\", Default: false},\n\t{Name: \"xid8_ops\", Method: \"BTREE\", Type: \"xid8\", Default: true},\n\t{Name: \"array_ops\", Method: \"GIN\", Type: \"anyarray\", Default: true},\n\t{Name: \"jsonb_ops\", Method: \"GIN\", Type: \"jsonb\", Default: true},\n\t{Name: \"jsonb_path_ops\", Method: \"GIN\", Type: \"jsonb\", Default: false},\n\t{Name: \"tsvector_ops\", Method: \"GIN\", Type: \"tsvector\", Default: true},\n\t{Name: \"box_ops\", Method: \"GIST\", Type: \"box\", Default: true},\n\t{Name: \"circle_ops\", Method: \"GIST\", Type: \"circle\", Default: true},\n\t{Name: \"inet_ops\", Method: \"GIST\", Type: \"inet\", Default: false},\n\t{Name: \"multirange_ops\", Method: \"GIST\", Type: \"anymultirange\", Default: true},\n\t{Name: \"point_ops\", Method: \"GIST\", Type: \"point\", Default: true},\n\t{Name: \"poly_ops\", Method: \"GIST\", Type: \"polygon\", Default: true},\n\t{Name: \"range_ops\", Method: \"GIST\", Type: \"anyrange\", Default: true},\n\t{Name: \"tsquery_ops\", Method: \"GIST\", Type: \"tsquery\", Default: true},\n\t{Name: \"tsvector_ops\", Method: \"GIST\", Type: \"tsvector\", Default: true},\n\t{Name: \"aclitem_ops\", Method: \"HASH\", Type: \"aclitem\", Default: true},\n\t{Name: \"array_ops\", Method: \"HASH\", Type: \"anyarray\", Default: true},\n\t{Name: \"bool_ops\", Method: \"HASH\", Type: \"boolean\", Default: true},\n\t{Name: \"bpchar_ops\", Method: \"HASH\", Type: \"character\", Default: true},\n\t{Name: \"bpchar_pattern_ops\", Method: \"HASH\", Type: \"character\", Default: false},\n\t{Name: \"bytea_ops\", Method: \"HASH\", Type: \"bytea\", Default: true},\n\t{Name: \"char_ops\", Method: \"HASH\", Type: \"char\", Default: true},\n\t{Name: \"cid_ops\", Method: \"HASH\", Type: \"cid\", Default: true},\n\t{Name: \"cidr_ops\", Method: \"HASH\", Type: \"inet\", Default: false},\n\t{Name: \"date_ops\", Method: \"HASH\", Type: \"date\", Default: true},\n\t{Name: \"enum_ops\", Method: \"HASH\", Type: \"anyenum\", Default: true},\n\t{Name: \"float4_ops\", Method: \"HASH\", Type: \"real\", Default: true},\n\t{Name: \"float8_ops\", Method: \"HASH\", Type: \"double precision\", Default: true},\n\t{Name: \"inet_ops\", Method: \"HASH\", Type: \"inet\", Default: true},\n\t{Name: \"int2_ops\", Method: \"HASH\", Type: \"smallint\", Default: true},\n\t{Name: \"int4_ops\", Method: \"HASH\", Type: \"integer\", Default: true},\n\t{Name: \"int8_ops\", Method: \"HASH\", Type: \"bigint\", Default: true},\n\t{Name: \"interval_ops\", Method: \"HASH\", Type: \"interval\", Default: true},\n\t{Name: \"jsonb_ops\", Method: \"HASH\", Type: \"jsonb\", Default: true},\n\t{Name: \"macaddr8_ops\", Method: \"HASH\", Type: \"macaddr8\", Default: true},\n\t{Name: \"macaddr_ops\", Method: \"HASH\", Type: \"macaddr\", Default: true},\n\t{Name: \"multirange_ops\", Method: \"HASH\", Type: \"anymultirange\", Default: true},\n\t{Name: \"name_ops\", Method: \"HASH\", Type: \"name\", Default: true},\n\t{Name: \"numeric_ops\", Method: \"HASH\", Type: \"numeric\", Default: true},\n\t{Name: \"oid_ops\", Method: \"HASH\", Type: \"oid\", Default: true},\n\t{Name: \"oidvector_ops\", Method: \"HASH\", Type: \"oidvector\", Default: true},\n\t{Name: \"pg_lsn_ops\", Method: \"HASH\", Type: \"pg_lsn\", Default: true},\n\t{Name: \"range_ops\", Method: \"HASH\", Type: \"anyrange\", Default: true},\n\t{Name: \"record_ops\", Method: \"HASH\", Type: \"record\", Default: true},\n\t{Name: \"text_ops\", Method: \"HASH\", Type: \"text\", Default: true},\n\t{Name: \"text_pattern_ops\", Method: \"HASH\", Type: \"text\", Default: false},\n\t{Name: \"tid_ops\", Method: \"HASH\", Type: \"tid\", Default: true},\n\t{Name: \"time_ops\", Method: \"HASH\", Type: \"time without time zone\", Default: true},\n\t{Name: \"timestamp_ops\", Method: \"HASH\", Type: \"timestamp without time zone\", Default: true},\n\t{Name: \"timestamptz_ops\", Method: \"HASH\", Type: \"timestamp with time zone\", Default: true},\n\t{Name: \"timetz_ops\", Method: \"HASH\", Type: \"time with time zone\", Default: true},\n\t{Name: \"uuid_ops\", Method: \"HASH\", Type: \"uuid\", Default: true},\n\t{Name: \"varchar_ops\", Method: \"HASH\", Type: \"text\", Default: false},\n\t{Name: \"varchar_pattern_ops\", Method: \"HASH\", Type: \"text\", Default: false},\n\t{Name: \"xid8_ops\", Method: \"HASH\", Type: \"xid8\", Default: true},\n\t{Name: \"xid_ops\", Method: \"HASH\", Type: \"xid\", Default: true},\n\t{Name: \"box_ops\", Method: \"SPGIST\", Type: \"box\", Default: true},\n\t{Name: \"inet_ops\", Method: \"SPGIST\", Type: \"inet\", Default: true},\n\t{Name: \"kd_point_ops\", Method: \"SPGIST\", Type: \"point\", Default: false},\n\t{Name: \"poly_ops\", Method: \"SPGIST\", Type: \"polygon\", Default: true},\n\t{Name: \"quad_point_ops\", Method: \"SPGIST\", Type: \"point\", Default: true},\n\t{Name: \"range_ops\", Method: \"SPGIST\", Type: \"anyrange\", Default: true},\n\t{Name: \"text_ops\", Method: \"SPGIST\", Type: \"text\", Default: true},\n\t{Name: \"gin_trgm_ops\", Method: \"GIN\", Type: \"text\", Default: false},\n\t{Name: \"gist_trgm_ops\", Method: \"GIN\", Type: \"text\", Default: false},\n\t{Name: \"btree_geography_ops\", Method: \"BTREE\", Type: \"geography\", Default: true},\n\t{Name: \"btree_geometry_ops\", Method: \"BTREE\", Type: \"geometry\", Default: true},\n\t{Name: \"gist_geography_ops\", Method: \"GIST\", Type: \"geography\", Default: true},\n\t{Name: \"gist_geometry_ops_2d\", Method: \"GIST\", Type: \"geometry\", Default: true},\n\t{Name: \"gist_geometry_ops_nd\", Method: \"GIST\", Type: \"geometry\", Default: false},\n\t{Name: \"gist_geometry_ops_3d\", Method: \"GIST\", Type: \"geometry\", Default: false},\n\t{Name: \"hash_geometry_ops\", Method: \"HASH\", Type: \"geometry\", Default: true},\n\t{Name: \"brin_geography_inclusion_ops\", Method: \"BRIN\", Type: \"geography\", Default: true},\n\t{Name: \"brin_geometry_inclusion_ops_2d\", Method: \"BRIN\", Type: \"geometry\", Default: true},\n\t{Name: \"brin_geometry_inclusion_ops_3d\", Method: \"BRIN\", Type: \"geometry\", Default: false},\n\t{Name: \"brin_geometry_inclusion_ops_4d\", Method: \"BRIN\", Type: \"geometry\", Default: false},\n\t{Name: \"spgist_geography_ops_nd\", Method: \"SPGIST\", Type: \"geography\", Default: true},\n\t{Name: \"spgist_geometry_ops_2d\", Method: \"SPGIST\", Type: \"geometry\", Default: true},\n\t{Name: \"spgist_geometry_ops_3d\", Method: \"SPGIST\", Type: \"geometry\", Default: false},\n\t{Name: \"spgist_geometry_ops_nd\", Method: \"SPGIST\", Type: \"geometry\", Default: false},\n}\n\nvar (\n\tmapOnce sync.Once\n\tbyName  map[string]struct{}\n)\n\n// HasClass reports if the given operator class name exists.\nfunc HasClass(name string) bool {\n\tmapOnce.Do(func() {\n\t\tbyName = make(map[string]struct{}, len(Classes))\n\t\tfor _, c := range Classes {\n\t\t\tbyName[c.Name] = struct{}{}\n\t\t}\n\t})\n\t_, ok := byName[name]\n\treturn ok\n}\n"
  },
  {
    "path": "sql/postgres/migrate_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// DefaultPlan provides basic planning capabilities for PostgreSQL dialects.\n// Note, it is recommended to call Open, create a new Driver and use its\n// migrate.PlanApplier when a database connection is available.\nvar DefaultPlan migrate.PlanApplier = &planApply{conn: &conn{ExecQuerier: sqlx.NoRows}}\n\n// A planApply provides migration capabilities for schema elements.\ntype planApply struct{ *conn }\n\n// PlanChanges returns a migration plan for the given schema changes.\nfunc (p *planApply) PlanChanges(ctx context.Context, name string, changes []schema.Change, opts ...migrate.PlanOption) (*migrate.Plan, error) {\n\ts := &state{\n\t\tconn: p.conn,\n\t\tPlan: migrate.Plan{\n\t\t\tName:          name,\n\t\t\tTransactional: true,\n\t\t},\n\t}\n\tfor _, o := range opts {\n\t\to(&s.PlanOptions)\n\t}\n\tif err := verifyChanges(ctx, changes); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := s.plan(changes); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := sqlx.SetReversible(&s.Plan); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &s.Plan, nil\n}\n\n// ApplyChanges applies the changes on the database. An error is returned\n// if the driver is unable to produce a plan to do so, or one of the statements\n// is failed or unsupported.\nfunc (p *planApply) ApplyChanges(ctx context.Context, changes []schema.Change, opts ...migrate.PlanOption) error {\n\treturn sqlx.ApplyChanges(ctx, changes, p, opts...)\n}\n\n// state represents the state of a planning. It is not part of\n// planApply so that multiple planning/applying can be called\n// in parallel.\ntype state struct {\n\t*conn\n\tmigrate.Plan\n\tmigrate.PlanOptions\n}\n\n// Exec executes the changes on the database. An error is returned\n// if one of the operations fail, or a change is not supported.\nfunc (s *state) plan(changes []schema.Change) error {\n\tif s.SchemaQualifier != nil {\n\t\tif err := sqlx.CheckChangesScope(s.PlanOptions, changes); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tplanned, err := s.topLevel(changes)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif s.PlanOptions.Mode != migrate.PlanModeUnsortedDump {\n\t\tif planned, err = s.detachCycles(planned); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tplanned = s.sortChanges(planned)\n\t}\n\tfor _, c := range planned {\n\t\tswitch c := c.(type) {\n\t\tcase *schema.AddTable:\n\t\t\terr = s.addTable(c)\n\t\tcase *schema.ModifyTable:\n\t\t\terr = s.modifyTable(c)\n\t\tcase *schema.RenameTable:\n\t\t\ts.renameTable(c)\n\t\tcase *schema.DropTable:\n\t\t\terr = s.dropTable(c)\n\t\tcase *schema.AddObject:\n\t\t\terr = s.addObject(c)\n\t\tcase *schema.ModifyObject:\n\t\t\terr = s.modifyObject(c)\n\t\tcase *schema.DropObject:\n\t\t\terr = s.dropObject(c)\n\t\tdefault:\n\t\t\terr = fmt.Errorf(\"unsupported change %T\", c)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// topLevel executes first the changes for creating or dropping schemas and\n// create objects that tables might depend on.\nfunc (s *state) topLevel(changes []schema.Change) ([]schema.Change, error) {\n\tplanned := make([]schema.Change, 0, len(changes))\n\tfor _, c := range changes {\n\t\tswitch c := c.(type) {\n\t\tcase *schema.AddSchema:\n\t\t\tb := s.Build(\"CREATE SCHEMA\")\n\t\t\t// Add the 'IF NOT EXISTS' clause if it is explicitly specified, or if the schema name is 'public'.\n\t\t\t// That is because the 'public' schema is automatically created by PostgreSQL in every new database,\n\t\t\t// and running the command with this clause will fail in case the schema already exists.\n\t\t\tif sqlx.Has(c.Extra, &schema.IfNotExists{}) || c.S.Name == \"public\" {\n\t\t\t\tb.P(\"IF NOT EXISTS\")\n\t\t\t}\n\t\t\tb.Ident(c.S.Name)\n\t\t\ts.append(&migrate.Change{\n\t\t\t\tCmd:     b.String(),\n\t\t\t\tSource:  c,\n\t\t\t\tReverse: s.Build(\"DROP SCHEMA\").Ident(c.S.Name).P(\"CASCADE\").String(),\n\t\t\t\tComment: fmt.Sprintf(\"Add new schema named %q\", c.S.Name),\n\t\t\t})\n\t\t\tif cm := (schema.Comment{}); sqlx.Has(c.S.Attrs, &cm) {\n\t\t\t\ts.append(s.schemaComment(c, c.S, cm.Text, \"\"))\n\t\t\t}\n\t\tcase *schema.ModifySchema:\n\t\t\tfor i := range c.Changes {\n\t\t\t\tswitch change := c.Changes[i].(type) {\n\t\t\t\t// Add schema attributes to an existing schema only if\n\t\t\t\t// it is different from the default server configuration.\n\t\t\t\tcase *schema.AddAttr:\n\t\t\t\t\ta, ok := change.A.(*schema.Comment)\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"unexpected schema AddAttr: %T\", change.A)\n\t\t\t\t\t}\n\t\t\t\t\ts.append(s.schemaComment(c, c.S, a.Text, \"\"))\n\t\t\t\tcase *schema.ModifyAttr:\n\t\t\t\t\tto, ok1 := change.To.(*schema.Comment)\n\t\t\t\t\tfrom, ok2 := change.From.(*schema.Comment)\n\t\t\t\t\tif !ok1 || !ok2 {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"unexpected schema ModifyAttr: (%T, %T)\", change.To, change.From)\n\t\t\t\t\t}\n\t\t\t\t\ts.append(s.schemaComment(c, c.S, to.Text, from.Text))\n\t\t\t\tdefault:\n\t\t\t\t\treturn nil, fmt.Errorf(\"unsupported ModifySchema change: %T\", change)\n\t\t\t\t}\n\t\t\t}\n\t\tcase *schema.DropSchema:\n\t\t\tb := s.Build(\"DROP SCHEMA\")\n\t\t\tif sqlx.Has(c.Extra, &schema.IfExists{}) {\n\t\t\t\tb.P(\"IF EXISTS\")\n\t\t\t}\n\t\t\tb.Ident(c.S.Name).P(\"CASCADE\")\n\t\t\ts.append(&migrate.Change{\n\t\t\t\tCmd:     b.String(),\n\t\t\t\tSource:  c,\n\t\t\t\tComment: fmt.Sprintf(\"Drop schema named %q\", c.S.Name),\n\t\t\t})\n\t\tcase *schema.RenameObject:\n\t\t\te1, ok1 := c.From.(*schema.EnumType)\n\t\t\te2, ok2 := c.To.(*schema.EnumType)\n\t\t\tif !ok1 || !ok2 {\n\t\t\t\treturn nil, fmt.Errorf(\"unsupported rename types %T -> %T\", c.From, c.To)\n\t\t\t}\n\t\t\ts.append(&migrate.Change{\n\t\t\t\tSource:  c,\n\t\t\t\tCmd:     s.Build(\"ALTER TYPE\").Ident(e1.T).P(\"RENAME TO\").Ident(e2.T).String(),\n\t\t\t\tReverse: s.Build(\"ALTER TYPE\").Ident(e2.T).P(\"RENAME TO\").Ident(e1.T).String(),\n\t\t\t\tComment: fmt.Sprintf(\"rename an enum from %q to %q\", e1.T, e2.T),\n\t\t\t})\n\t\tdefault:\n\t\t\tplanned = append(planned, c)\n\t\t}\n\t}\n\treturn planned, nil\n}\n\n// addTable builds and executes the query for creating a table in a schema.\nfunc (s *state) addTable(add *schema.AddTable) error {\n\tvar (\n\t\terrs []string\n\t\tb    = s.Build(\"CREATE TABLE\")\n\t)\n\tif sqlx.Has(add.Extra, &schema.IfNotExists{}) {\n\t\tb.P(\"IF NOT EXISTS\")\n\t}\n\tb.Table(add.T)\n\tb.WrapIndent(func(b *sqlx.Builder) {\n\t\tb.MapIndent(add.T.Columns, func(i int, b *sqlx.Builder) {\n\t\t\tif err := s.column(b, add.T.Columns[i]); err != nil {\n\t\t\t\terrs = append(errs, err.Error())\n\t\t\t}\n\t\t})\n\t\tif pk := add.T.PrimaryKey; pk != nil {\n\t\t\tb.Comma().NL().P(\"PRIMARY KEY\")\n\t\t\tif err := s.index(b, pk); err != nil {\n\t\t\t\terrs = append(errs, err.Error())\n\t\t\t}\n\t\t}\n\t\tfor _, idx := range add.T.Indexes {\n\t\t\t_, okU := uniqueConst(idx.Attrs)\n\t\t\t_, okE := excludeConst(idx.Attrs)\n\t\t\tif okU || okE {\n\t\t\t\tb.Comma().NL()\n\t\t\t\tif err := s.constraint(b, idx); err != nil {\n\t\t\t\t\terrs = append(errs, err.Error())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif len(add.T.ForeignKeys) > 0 {\n\t\t\tb.Comma()\n\t\t\ts.fks(b, add.T.ForeignKeys...)\n\t\t}\n\t\tfor _, attr := range add.T.Attrs {\n\t\t\tif c, ok := attr.(*schema.Check); ok {\n\t\t\t\tb.Comma().NL()\n\t\t\t\tcheck(b, c)\n\t\t\t}\n\t\t}\n\t})\n\tif p := (Partition{}); sqlx.Has(add.T.Attrs, &p) {\n\t\ts, err := formatPartition(p)\n\t\tif err != nil {\n\t\t\terrs = append(errs, err.Error())\n\t\t}\n\t\tb.P(s)\n\t}\n\tif len(errs) > 0 {\n\t\treturn fmt.Errorf(\"create table %q: %s\", add.T.Name, strings.Join(errs, \", \"))\n\t}\n\ts.append(&migrate.Change{\n\t\tCmd:     b.String(),\n\t\tSource:  add,\n\t\tComment: fmt.Sprintf(\"create %q table\", add.T.Name),\n\t\tReverse: s.Build(\"DROP TABLE\").Table(add.T).String(),\n\t})\n\tfor _, idx := range add.T.Indexes {\n\t\t_, okU := uniqueConst(idx.Attrs)\n\t\t_, okE := excludeConst(idx.Attrs)\n\t\tif !okU && !okE {\n\t\t\t// Indexes do not need to be created concurrently on new tables.\n\t\t\tif err := s.addIndexes(add, add.T, &schema.AddIndex{I: idx}); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\ts.addComments(add, add.T)\n\ts.addTableAttrs(add)\n\treturn nil\n}\n\n// dropTable builds and executes the query for dropping a table from a schema.\nfunc (s *state) dropTable(drop *schema.DropTable) error {\n\tcmd := &changeGroup{}\n\trs := &state{\n\t\tconn:        s.conn,\n\t\tPlanOptions: s.PlanOptions,\n\t}\n\tif err := rs.addTable(&schema.AddTable{T: drop.T}); err != nil {\n\t\treturn fmt.Errorf(\"calculate reverse for drop table %q: %w\", drop.T.Name, err)\n\t}\n\tb := s.Build(\"DROP TABLE\")\n\tif sqlx.Has(drop.Extra, &schema.IfExists{}) {\n\t\tb.P(\"IF EXISTS\")\n\t}\n\tb.Table(drop.T)\n\tif sqlx.Has(drop.Extra, &Cascade{}) {\n\t\tb.P(\"CASCADE\")\n\t}\n\tcmd.main = &migrate.Change{\n\t\tCmd:     b.String(),\n\t\tSource:  drop,\n\t\tComment: fmt.Sprintf(\"drop %q table\", drop.T.Name),\n\t\t// The reverse of 'DROP TABLE' might be a multi\n\t\t// statement operation. e.g., table with indexes.\n\t\tReverse: func() any {\n\t\t\tcmd := make([]string, len(rs.Changes))\n\t\t\tfor i, c := range rs.Changes {\n\t\t\t\tcmd[i] = c.Cmd\n\t\t\t}\n\t\t\tif len(cmd) == 1 {\n\t\t\t\treturn cmd[0]\n\t\t\t}\n\t\t\treturn cmd\n\t\t}(),\n\t}\n\tcmd.append(s)\n\treturn nil\n}\n\n// modifyTable builds the statements that bring the table into its modified state.\nfunc (s *state) modifyTable(modify *schema.ModifyTable) error {\n\tvar (\n\t\talter   []schema.Change\n\t\taddI    []*schema.AddIndex\n\t\tdropI   []*schema.DropIndex\n\t\tchanges []*migrate.Change\n\t)\n\tfor _, change := range skipAutoChanges(modify.Changes) {\n\t\tswitch change := change.(type) {\n\t\tcase *schema.ModifyAttr:\n\t\t\tif _, ok := change.From.(*schema.Comment); !ok {\n\t\t\t\talter = append(alter, change)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfrom, to, err := commentChange(change)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// Comments are not part of the ALTER command.\n\t\t\tchanges = append(changes, s.tableComment(modify, modify.T, to, from))\n\t\tcase *schema.AddAttr:\n\t\t\tfrom, to, err := commentChange(change)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// Comments are not part of the ALTER command.\n\t\t\tchanges = append(changes, s.tableComment(modify, modify.T, to, from))\n\t\tcase *schema.DropAttr:\n\t\t\treturn fmt.Errorf(\"unsupported change type: %T\", change)\n\t\tcase *schema.AddIndex:\n\t\t\tif c := (schema.Comment{}); sqlx.Has(change.I.Attrs, &c) {\n\t\t\t\tchanges = append(changes, s.indexComment(modify, modify.T, change.I, c.Text, \"\"))\n\t\t\t}\n\t\t\t_, okU := uniqueConst(change.I.Attrs)\n\t\t\t_, okE := excludeConst(change.I.Attrs)\n\t\t\t// Unlike ADD INDEX statements that are executed separately,\n\t\t\t// ADD CONSTRAINT are added to the ALTER TABLE statement below.\n\t\t\tif okU || okE {\n\t\t\t\talter = append(alter, change)\n\t\t\t} else {\n\t\t\t\taddI = append(addI, change)\n\t\t\t}\n\t\tcase *schema.DropIndex:\n\t\t\t_, okU := uniqueConst(change.I.Attrs)\n\t\t\t_, okE := excludeConst(change.I.Attrs)\n\t\t\t// Unlike DROP INDEX statements that are executed separately,\n\t\t\t// DROP CONSTRAINT are added to the ALTER TABLE statement below.\n\t\t\tif okU || okE {\n\t\t\t\talter = append(alter, change)\n\t\t\t} else {\n\t\t\t\tdropI = append(dropI, change)\n\t\t\t}\n\t\tcase *schema.ModifyPrimaryKey:\n\t\t\t// Primary key modification needs to be split into \"Drop\" and \"Add\"\n\t\t\t// because the new key may include columns that have not been added yet.\n\t\t\talter = append(alter, &schema.DropPrimaryKey{\n\t\t\t\tP: change.From,\n\t\t\t}, &schema.AddPrimaryKey{\n\t\t\t\tP: change.To,\n\t\t\t})\n\t\tcase *schema.ModifyIndex:\n\t\t\tk := change.Change\n\t\t\tif change.Change.Is(schema.ChangeComment) {\n\t\t\t\tfrom, to, err := commentChange(sqlx.CommentDiff(change.From.Attrs, change.To.Attrs))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tchanges = append(changes, s.indexComment(modify, modify.T, change.To, to, from))\n\t\t\t\t// If only the comment of the index was changed.\n\t\t\t\tif k &= ^schema.ChangeComment; k.Is(schema.NoChange) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif addU, ok := indexToUnique(change); ok {\n\t\t\t\talter = append(alter, addU)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Index (or constraint) modification requires rebuilding the index.\n\t\t\t_, fromU := uniqueConst(change.From.Attrs)\n\t\t\t_, fromE := excludeConst(change.From.Attrs)\n\t\t\tif fromU || fromE {\n\t\t\t\talter = append(alter, &schema.DropIndex{I: change.From})\n\t\t\t} else {\n\t\t\t\tdropI = append(dropI, &schema.DropIndex{I: change.From})\n\t\t\t}\n\t\t\t_, toU := uniqueConst(change.To.Attrs)\n\t\t\t_, toE := excludeConst(change.To.Attrs)\n\t\t\tif toU || toE {\n\t\t\t\talter = append(alter, &schema.AddIndex{I: change.To})\n\t\t\t} else {\n\t\t\t\taddI = append(addI, &schema.AddIndex{I: change.To})\n\t\t\t}\n\t\tcase *schema.RenameIndex:\n\t\t\tchanges = append(changes, &migrate.Change{\n\t\t\t\tSource:  change,\n\t\t\t\tComment: fmt.Sprintf(\"rename an index from %q to %q\", change.From.Name, change.To.Name),\n\t\t\t\tCmd:     s.Build(\"ALTER INDEX\").SchemaResource(modify.T.Schema, change.From.Name).P(\"RENAME TO\").Ident(change.To.Name).String(),\n\t\t\t\tReverse: s.Build(\"ALTER INDEX\").SchemaResource(modify.T.Schema, change.To.Name).P(\"RENAME TO\").Ident(change.From.Name).String(),\n\t\t\t})\n\t\tcase *schema.ModifyForeignKey:\n\t\t\t// Foreign-key modification is translated into 2 steps.\n\t\t\t// Dropping the current foreign key and creating a new one.\n\t\t\talter = append(alter, &schema.DropForeignKey{\n\t\t\t\tF: change.From,\n\t\t\t}, &schema.AddForeignKey{\n\t\t\t\tF: change.To,\n\t\t\t})\n\t\tcase *schema.AddColumn:\n\t\t\tif c := (schema.Comment{}); sqlx.Has(change.C.Attrs, &c) {\n\t\t\t\tchanges = append(changes, s.columnComment(modify, modify.T, change.C, c.Text, \"\"))\n\t\t\t}\n\t\t\talter = append(alter, change)\n\t\tcase *schema.ModifyColumn:\n\t\t\tk := change.Change\n\t\t\tif change.Change.Is(schema.ChangeComment) {\n\t\t\t\tfrom, to, err := commentChange(sqlx.CommentDiff(change.From.Attrs, change.To.Attrs))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tchanges = append(changes, s.columnComment(modify, modify.T, change.To, to, from))\n\t\t\t\t// If only the comment of the column was changed.\n\t\t\t\tif k &= ^schema.ChangeComment; k.Is(schema.NoChange) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\talter = append(alter, &schema.ModifyColumn{To: change.To, From: change.From, Change: k, Extra: change.Extra})\n\t\tcase *schema.RenameColumn:\n\t\t\t// \"RENAME COLUMN\" cannot be combined with other alterations.\n\t\t\tb := s.Build(\"ALTER TABLE\").Table(modify.T).P(\"RENAME COLUMN\")\n\t\t\tr := b.Clone()\n\t\t\tchanges = append(changes, &migrate.Change{\n\t\t\t\tSource:  change,\n\t\t\t\tComment: fmt.Sprintf(\"rename a column from %q to %q\", change.From.Name, change.To.Name),\n\t\t\t\tCmd:     b.Ident(change.From.Name).P(\"TO\").Ident(change.To.Name).String(),\n\t\t\t\tReverse: r.Ident(change.To.Name).P(\"TO\").Ident(change.From.Name).String(),\n\t\t\t})\n\t\tdefault:\n\t\t\talter = append(alter, change)\n\t\t}\n\t}\n\tif err := s.dropIndexes(modify, modify.T, dropI...); err != nil {\n\t\treturn err\n\t}\n\tif len(alter) > 0 {\n\t\tif err := s.alterTable(modify.T, alter); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := s.addIndexes(modify, modify.T, addI...); err != nil {\n\t\treturn err\n\t}\n\ts.append(changes...)\n\treturn nil\n}\n\ntype (\n\t// AddUniqueConstraint to the table using the given index. Note, if the index\n\t// name does not match the unique constraint name, PostgreSQL implicitly renames\n\t// it to the constraint name.\n\tAddUniqueConstraint struct {\n\t\tschema.Change\n\t\tName  string        // Name of the constraint.\n\t\tUsing *schema.Index // Index to use for the constraint.\n\t}\n\t// AddPKConstraint to the table using the given index. Note, if the index\n\t// name does not match the primary-key constraint name, PostgreSQL implicitly\n\t// renames it to the constraint name.\n\tAddPKConstraint struct {\n\t\tschema.Change\n\t\tName  string        // Name of the constraint.\n\t\tUsing *schema.Index // Index to use for the constraint.\n\t}\n)\n\n// alterTable modifies the given table by executing on it a list of changes in one SQL statement.\nfunc (s *state) alterTable(t *schema.Table, changes []schema.Change) error {\n\tvar (\n\t\treverse    []schema.Change\n\t\treversible = true\n\t)\n\t// Constraints drop should be executed first.\n\tsort.SliceStable(changes, func(i, j int) bool {\n\t\treturn dropConst(changes[i]) && !dropConst(changes[j])\n\t})\n\tbuild := func(alter *changeGroup, changes []schema.Change) (string, error) {\n\t\tb := s.Build(\"ALTER TABLE\").Table(t)\n\t\terr := b.MapCommaErr(changes, func(i int, b *sqlx.Builder) error {\n\t\t\tswitch change := changes[i].(type) {\n\t\t\tcase *schema.AddColumn:\n\t\t\t\tb.P(\"ADD COLUMN\")\n\t\t\t\tif err := s.column(b, change.C); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.DropColumn{C: change.C})\n\t\t\tcase *schema.ModifyColumn:\n\t\t\t\tif err := s.alterColumn(b, alter, t, change); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif change.Change.Is(schema.ChangeGenerated) {\n\t\t\t\t\treversible = false\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.ModifyColumn{\n\t\t\t\t\tFrom:   change.To,\n\t\t\t\t\tTo:     change.From,\n\t\t\t\t\tChange: change.Change & ^schema.ChangeGenerated,\n\t\t\t\t})\n\t\t\tcase *schema.DropColumn:\n\t\t\t\tb.P(\"DROP COLUMN\").Ident(change.C.Name)\n\t\t\t\treverse = append(reverse, &schema.AddColumn{C: change.C})\n\t\t\tcase *AddUniqueConstraint:\n\t\t\t\tb.P(\"ADD\")\n\t\t\t\tdrop := change.Using\n\t\t\t\tif change.Name != \"\" {\n\t\t\t\t\tb.P(\"CONSTRAINT\").Ident(change.Name)\n\t\t\t\t\tdrop = sqlx.P(*change.Using)\n\t\t\t\t\tdrop.Name = change.Name\n\t\t\t\t}\n\t\t\t\tb.P(\"UNIQUE USING INDEX\").Ident(change.Using.Name)\n\t\t\t\t// Translated to the DROP CONSTRAINT below,\n\t\t\t\t// which drops the index as well.\n\t\t\t\treverse = append(reverse, &schema.DropIndex{I: drop})\n\t\t\tcase *AddPKConstraint:\n\t\t\t\tb.P(\"ADD\")\n\t\t\t\tdrop := change.Using\n\t\t\t\tif change.Name != \"\" {\n\t\t\t\t\tb.P(\"CONSTRAINT\").Ident(change.Name)\n\t\t\t\t\tdrop = sqlx.P(*change.Using)\n\t\t\t\t\tdrop.Name = change.Name\n\t\t\t\t}\n\t\t\t\tb.P(\"PRIMARY KEY USING INDEX\").Ident(change.Using.Name)\n\t\t\t\t// Translated to the DROP CONSTRAINT below,\n\t\t\t\t// which drops the index as well.\n\t\t\t\treverse = append(reverse, &schema.DropPrimaryKey{P: drop})\n\t\t\tcase *schema.AddIndex:\n\t\t\t\tb.P(\"ADD\")\n\t\t\t\tif err := s.constraint(b, change.I); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.DropIndex{I: change.I})\n\t\t\tcase *schema.DropIndex:\n\t\t\t\tb.P(\"DROP CONSTRAINT\").Ident(change.I.Name)\n\t\t\t\treverse = append(reverse, &schema.AddIndex{I: change.I})\n\t\t\tcase *schema.AddPrimaryKey:\n\t\t\t\tb.P(\"ADD PRIMARY KEY\")\n\t\t\t\tif err := s.index(b, change.P); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.DropPrimaryKey{P: change.P})\n\t\t\tcase *schema.DropPrimaryKey:\n\t\t\t\tb.P(\"DROP CONSTRAINT\").Ident(pkName(t, change.P))\n\t\t\t\treverse = append(reverse, &schema.AddPrimaryKey{P: change.P})\n\t\t\tcase *schema.AddForeignKey:\n\t\t\t\ts.fks(b.P(\"ADD\"), change.F)\n\t\t\t\tif sqlx.Has(change.Extra, &NotValid{}) {\n\t\t\t\t\tb.P(\"NOT VALID\")\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.DropForeignKey{F: change.F})\n\t\t\tcase *schema.DropForeignKey:\n\t\t\t\tb.P(\"DROP CONSTRAINT\")\n\t\t\t\tif sqlx.Has(change.Extra, &schema.IfExists{}) {\n\t\t\t\t\tb.P(\"IF EXISTS\")\n\t\t\t\t}\n\t\t\t\tb.Ident(change.F.Symbol)\n\t\t\t\treverse = append(reverse, &schema.AddForeignKey{F: change.F})\n\t\t\tcase *schema.AddCheck:\n\t\t\t\tcheck(b.P(\"ADD\"), change.C)\n\t\t\t\tif sqlx.Has(change.Extra, &NotValid{}) {\n\t\t\t\t\tb.P(\"NOT VALID\")\n\t\t\t\t}\n\t\t\t\t// Reverse operation is supported if\n\t\t\t\t// the constraint name is not generated.\n\t\t\t\tif reversible = reversible && change.C.Name != \"\"; reversible {\n\t\t\t\t\treverse = append(reverse, &schema.DropCheck{C: change.C})\n\t\t\t\t}\n\t\t\tcase *schema.DropCheck:\n\t\t\t\tb.P(\"DROP CONSTRAINT\").Ident(change.C.Name)\n\t\t\t\treverse = append(reverse, &schema.AddCheck{C: change.C})\n\t\t\tcase *schema.ModifyCheck:\n\t\t\t\tswitch {\n\t\t\t\tcase change.From.Name == \"\":\n\t\t\t\t\treturn errors.New(\"cannot modify unnamed check constraint\")\n\t\t\t\tcase change.From.Name != change.To.Name:\n\t\t\t\t\treturn fmt.Errorf(\"mismatch check constraint names: %q != %q\", change.From.Name, change.To.Name)\n\t\t\t\tcase change.From.Expr != change.To.Expr,\n\t\t\t\t\tsqlx.Has(change.From.Attrs, &NoInherit{}) && !sqlx.Has(change.To.Attrs, &NoInherit{}),\n\t\t\t\t\t!sqlx.Has(change.From.Attrs, &NoInherit{}) && sqlx.Has(change.To.Attrs, &NoInherit{}):\n\t\t\t\t\tb.P(\"DROP CONSTRAINT\").Ident(change.From.Name).Comma().P(\"ADD\")\n\t\t\t\t\tcheck(b, change.To)\n\t\t\t\tdefault:\n\t\t\t\t\treturn errors.New(\"unknown check constraint change\")\n\t\t\t\t}\n\t\t\t\treverse = append(reverse, &schema.ModifyCheck{\n\t\t\t\t\tFrom: change.To,\n\t\t\t\t\tTo:   change.From,\n\t\t\t\t})\n\t\t\tcase *schema.ModifyAttr:\n\t\t\t\ts.alterTableAttr(b, change)\n\t\t\t\treverse = append(reverse, &schema.ModifyAttr{\n\t\t\t\t\tFrom: change.To,\n\t\t\t\t\tTo:   change.From,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\treturn b.String(), nil\n\t}\n\tcmd := &changeGroup{}\n\tstmt, err := build(cmd, changes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"alter table %q: %v\", t.Name, err)\n\t}\n\tcmd.main = &migrate.Change{\n\t\tCmd: stmt,\n\t\tSource: &schema.ModifyTable{\n\t\t\tT:       t,\n\t\t\tChanges: changes,\n\t\t},\n\t\tComment: fmt.Sprintf(\"modify %q table\", t.Name),\n\t}\n\tif reversible {\n\t\t// Changes should be reverted in\n\t\t// a reversed order they were created.\n\t\tsqlx.ReverseChanges(reverse)\n\t\tif cmd.main.Reverse, err = build(&changeGroup{}, reverse); err != nil {\n\t\t\treturn fmt.Errorf(\"reverse alter table %q: %v\", t.Name, err)\n\t\t}\n\t}\n\tcmd.append(s)\n\treturn nil\n}\n\n// changeGroup describes an alter table migrate.Change where its main command\n// can be supported by additional statements before and after it is executed.\ntype changeGroup struct {\n\tmain          *migrate.Change\n\tbefore, after []*migrate.Change\n}\n\nfunc (a *changeGroup) append(s *state) {\n\ts.append(a.before...)\n\ts.append(a.main)\n\ts.append(a.after...)\n}\n\nfunc (s *state) alterColumn(b *sqlx.Builder, alter *changeGroup, t *schema.Table, c *schema.ModifyColumn) error {\n\tfor k := c.Change; !k.Is(schema.NoChange); {\n\t\tb.P(\"ALTER COLUMN\").Ident(c.To.Name)\n\t\tswitch {\n\t\tcase k.Is(schema.ChangeType):\n\t\t\tif err := s.alterType(b, alter, t, c); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tk &= ^schema.ChangeType\n\t\tcase k.Is(schema.ChangeNull) && c.To.Type.Null:\n\t\t\tif t, ok := c.To.Type.Type.(*SerialType); ok {\n\t\t\t\treturn fmt.Errorf(\"NOT NULL constraint is required for %s column %q\", t.T, c.To.Name)\n\t\t\t}\n\t\t\tb.P(\"DROP NOT NULL\")\n\t\t\tk &= ^schema.ChangeNull\n\t\tcase k.Is(schema.ChangeNull) && !c.To.Type.Null:\n\t\t\tb.P(\"SET NOT NULL\")\n\t\t\tk &= ^schema.ChangeNull\n\t\tcase k.Is(schema.ChangeDefault) && c.To.Default == nil:\n\t\t\tb.P(\"DROP DEFAULT\")\n\t\t\tk &= ^schema.ChangeDefault\n\t\tcase k.Is(schema.ChangeDefault) && c.To.Default != nil:\n\t\t\ts.columnDefault(b.P(\"SET\"), c.To)\n\t\t\tk &= ^schema.ChangeDefault\n\t\tcase k.Is(schema.ChangeAttr):\n\t\t\ttoI, ok := identity(c.To.Attrs)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected attribute change (expect IDENTITY): %v\", c.To.Attrs)\n\t\t\t}\n\t\t\t// The syntax for altering identity columns is identical to sequence_options.\n\t\t\t// https://www.postgresql.org/docs/current/sql-altersequence.html\n\t\t\tb.P(\"SET GENERATED\", toI.Generation, \"SET START WITH\", strconv.FormatInt(toI.Sequence.Start, 10), \"SET INCREMENT BY\", strconv.FormatInt(toI.Sequence.Increment, 10))\n\t\t\t// Skip SEQUENCE RESTART in case the \"start value\" is less than the \"current value\" in one\n\t\t\t// of the states (inspected and desired), because this function is used for both UP and DOWN.\n\t\t\tif fromI, ok := identity(c.From.Attrs); (!ok || fromI.Sequence.Last < toI.Sequence.Start) && toI.Sequence.Last < toI.Sequence.Start {\n\t\t\t\tb.P(\"RESTART\")\n\t\t\t}\n\t\t\tk &= ^schema.ChangeAttr\n\t\tcase k.Is(schema.ChangeGenerated):\n\t\t\tif sqlx.Has(c.To.Attrs, &schema.GeneratedExpr{}) {\n\t\t\t\treturn fmt.Errorf(\"unexpected generation expression change (expect DROP EXPRESSION): %v\", c.To.Attrs)\n\t\t\t}\n\t\t\tb.P(\"DROP EXPRESSION\")\n\t\t\tk &= ^schema.ChangeGenerated\n\t\tdefault: // e.g. schema.ChangeComment.\n\t\t\treturn fmt.Errorf(\"unexpected column change: %d\", k)\n\t\t}\n\t\tif !k.Is(schema.NoChange) {\n\t\t\tb.Comma()\n\t\t}\n\t}\n\treturn nil\n}\n\n// alterType appends the clause(s) to alter the column type and assuming the\n// \"ALTER COLUMN <Name>\" was called before by the alterColumn function.\nfunc (s *state) alterType(b *sqlx.Builder, alter *changeGroup, t *schema.Table, c *schema.ModifyColumn) error {\n\t// Commands for creating and dropping serial sequences.\n\tcreateDropSeq := func(st *SerialType) (string, string, string) {\n\t\tseq := fmt.Sprintf(`%s%q`, s.schemaPrefix(t.Schema), st.sequence(t, c.To))\n\t\tdrop := s.Build(\"DROP SEQUENCE IF EXISTS\").P(seq).String()\n\t\tcreate := s.Build(\"CREATE SEQUENCE IF NOT EXISTS\").P(seq, \"OWNED BY\").\n\t\t\tP(fmt.Sprintf(`%s%q.%q`, s.schemaPrefix(t.Schema), t.Name, c.To.Name)).\n\t\t\tString()\n\t\treturn create, drop, seq\n\t}\n\ttoS, toHas := c.To.Type.Type.(*SerialType)\n\tfromS, fromHas := c.From.Type.Type.(*SerialType)\n\tswitch {\n\t// Sequence was dropped.\n\tcase fromHas && !toHas:\n\t\tb.P(\"DROP DEFAULT\")\n\t\tcreate, drop, _ := createDropSeq(fromS)\n\t\t// Sequence should be deleted after it was dropped\n\t\t// from the DEFAULT value.\n\t\talter.after = append(alter.after, &migrate.Change{\n\t\t\tSource:  c,\n\t\t\tComment: fmt.Sprintf(\"drop sequence used by serial column %q\", c.From.Name),\n\t\t\tCmd:     drop,\n\t\t\tReverse: create,\n\t\t})\n\t\ttoT, err := FormatType(c.To.Type.Type)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfromT, err := FormatType(fromS.IntegerType())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Underlying type was changed. e.g. serial to bigint.\n\t\tif toT != fromT {\n\t\t\tb.Comma().P(\"ALTER COLUMN\").Ident(c.To.Name).P(\"TYPE\", toT)\n\t\t}\n\t// Sequence was added.\n\tcase !fromHas && toHas:\n\t\tcreate, drop, seq := createDropSeq(toS)\n\t\t// Sequence should be created before it is used by the\n\t\t// column DEFAULT value.\n\t\talter.before = append(alter.before, &migrate.Change{\n\t\t\tSource:  c,\n\t\t\tComment: fmt.Sprintf(\"create sequence for serial column %q\", c.To.Name),\n\t\t\tCmd:     create,\n\t\t\tReverse: drop,\n\t\t})\n\t\tb.P(\"SET DEFAULT\", fmt.Sprintf(\"nextval('%s')\", seq))\n\t\ttoT, err := FormatType(toS.IntegerType())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfromT, err := FormatType(c.From.Type.Type)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Underlying type was changed. e.g. integer to bigserial (bigint).\n\t\tif toT != fromT {\n\t\t\tb.Comma().P(\"ALTER COLUMN\").Ident(c.To.Name).P(\"TYPE\", toT)\n\t\t}\n\t// Serial type was changed. e.g. serial to bigserial.\n\tcase fromHas && toHas:\n\t\tf, err := FormatType(toS.IntegerType())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tb.P(\"TYPE\", f)\n\tdefault:\n\t\tvar (\n\t\t\tf   string\n\t\t\terr error\n\t\t)\n\t\tif e, ok := c.To.Type.Type.(*schema.EnumType); ok {\n\t\t\tf = s.enumIdent(e)\n\t\t} else if f, err = FormatType(c.To.Type.Type); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tb.P(\"TYPE\", f)\n\t}\n\tif collate := (schema.Collation{}); sqlx.Has(c.To.Attrs, &collate) {\n\t\tb.P(\"COLLATE\").Ident(collate.V)\n\t}\n\tif using := (ConvertUsing{}); sqlx.Has(c.Extra, &using) {\n\t\tb.P(\"USING\", using.X)\n\t}\n\treturn nil\n}\n\nfunc (s *state) renameTable(c *schema.RenameTable) {\n\ts.append(&migrate.Change{\n\t\tSource:  c,\n\t\tComment: fmt.Sprintf(\"rename a table from %q to %q\", c.From.Name, c.To.Name),\n\t\tCmd:     s.Build(\"ALTER TABLE\").Table(c.From).P(\"RENAME TO\").Table(c.To).String(),\n\t\tReverse: s.Build(\"ALTER TABLE\").Table(c.To).P(\"RENAME TO\").Table(c.From).String(),\n\t})\n}\n\nfunc (s *state) addComments(src schema.Change, t *schema.Table) {\n\tvar c schema.Comment\n\tif sqlx.Has(t.Attrs, &c) && c.Text != \"\" {\n\t\ts.append(s.tableComment(src, t, c.Text, \"\"))\n\t}\n\tfor i := range t.Columns {\n\t\tif sqlx.Has(t.Columns[i].Attrs, &c) && c.Text != \"\" {\n\t\t\ts.append(s.columnComment(src, t, t.Columns[i], c.Text, \"\"))\n\t\t}\n\t}\n\tfor i := range t.Indexes {\n\t\tif sqlx.Has(t.Indexes[i].Attrs, &c) && c.Text != \"\" {\n\t\t\ts.append(s.indexComment(src, t, t.Indexes[i], c.Text, \"\"))\n\t\t}\n\t}\n}\n\nfunc (s *state) schemaComment(src schema.Change, sc *schema.Schema, to, from string) *migrate.Change {\n\tb := s.Build(\"COMMENT ON SCHEMA\").Ident(sc.Name).P(\"IS\")\n\treturn &migrate.Change{\n\t\tCmd:     b.Clone().P(quote(to)).String(),\n\t\tSource:  src,\n\t\tComment: fmt.Sprintf(\"set comment to schema: %q\", sc.Name),\n\t\tReverse: b.Clone().P(quote(from)).String(),\n\t}\n}\n\nfunc (s *state) tableComment(src schema.Change, t *schema.Table, to, from string) *migrate.Change {\n\tb := s.Build(\"COMMENT ON TABLE\").Table(t).P(\"IS\")\n\treturn &migrate.Change{\n\t\tCmd:     b.Clone().P(quote(to)).String(),\n\t\tSource:  src,\n\t\tComment: fmt.Sprintf(\"set comment to table: %q\", t.Name),\n\t\tReverse: b.Clone().P(quote(from)).String(),\n\t}\n}\n\nfunc (s *state) columnComment(src schema.Change, t *schema.Table, c *schema.Column, to, from string) *migrate.Change {\n\tb := s.Build(\"COMMENT ON COLUMN\").TableResource(t, c)\n\tb.P(\"IS\")\n\treturn &migrate.Change{\n\t\tCmd:     b.Clone().P(quote(to)).String(),\n\t\tSource:  src,\n\t\tComment: fmt.Sprintf(\"set comment to column: %q on table: %q\", c.Name, t.Name),\n\t\tReverse: b.Clone().P(quote(from)).String(),\n\t}\n}\n\nfunc (s *state) indexComment(src schema.Change, t *schema.Table, idx *schema.Index, to, from string) *migrate.Change {\n\tb := s.Build(\"COMMENT ON INDEX\").SchemaResource(t.Schema, idx.Name).P(\"IS\")\n\treturn &migrate.Change{\n\t\tCmd:     b.Clone().P(quote(to)).String(),\n\t\tSource:  src,\n\t\tComment: fmt.Sprintf(\"set comment to index: %q on table: %q\", idx.Name, t.Name),\n\t\tReverse: b.Clone().P(quote(from)).String(),\n\t}\n}\n\nfunc (s *state) dropIndexes(src schema.Change, t *schema.Table, drops ...*schema.DropIndex) error {\n\tadds := make([]*schema.AddIndex, len(drops))\n\tfor i, d := range drops {\n\t\tadds[i] = &schema.AddIndex{I: d.I, Extra: d.Extra}\n\t}\n\trs := &state{conn: s.conn, PlanOptions: s.PlanOptions}\n\tif err := rs.addIndexes(src, t, adds...); err != nil {\n\t\treturn err\n\t}\n\tfor i, add := range adds {\n\t\ts.append(&migrate.Change{\n\t\t\tCmd:     rs.Changes[i].Reverse.(string),\n\t\t\tSource:  src,\n\t\t\tComment: fmt.Sprintf(\"drop index %q from table: %q\", add.I.Name, t.Name),\n\t\t\tReverse: rs.Changes[i].Cmd,\n\t\t})\n\t}\n\treturn nil\n}\n\nfunc (s *state) alterEnum(modify *schema.ModifyObject) error {\n\tfrom, ok1 := modify.From.(*schema.EnumType)\n\tto, ok2 := modify.To.(*schema.EnumType)\n\tif !ok1 || !ok2 {\n\t\treturn fmt.Errorf(\"altering objects (%T) to (%T) is not supported\", modify.From, modify.To)\n\t}\n\tfromV := make(map[string]int, len(from.Values))\n\tfor i, v := range from.Values {\n\t\tfromV[v] = i\n\t}\n\ttoV := make(map[string]int, len(to.Values))\n\tfor i, v := range from.Values {\n\t\ttoV[v] = i\n\t}\n\tfor v := range fromV {\n\t\tif _, ok := toV[v]; !ok {\n\t\t\treturn fmt.Errorf(\"dropping value %q from enum %q is not supported\", v, from.T)\n\t\t}\n\t}\n\tvar (\n\t\tat   int\n\t\tname = s.enumIdent(from)\n\t)\n\tfor i, v := range to.Values {\n\t\tb := s.Build(\"ALTER TYPE\").P(name, \"ADD VALUE\", quote(v))\n\t\tswitch j, ok := fromV[v]; {\n\t\tcase !ok:\n\t\t\tif i == 0 && len(from.Values) > 0 {\n\t\t\t\tb.P(\"BEFORE\").P(quote(from.Values[0]))\n\t\t\t} else if i > 0 && at != len(from.Values) {\n\t\t\t\tb.P(\"AFTER\").P(quote(to.Values[i-1]))\n\t\t\t}\n\t\t\ts.append(&migrate.Change{\n\t\t\t\tCmd:     b.String(),\n\t\t\t\tComment: fmt.Sprintf(\"add value to enum type: %q\", from.T),\n\t\t\t})\n\t\tcase ok && j == at:\n\t\t\tat++\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"reordering enum %q value %q is not supported\", from.T, v)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *state) addIndexes(src schema.Change, t *schema.Table, adds ...*schema.AddIndex) error {\n\tfor _, add := range adds {\n\t\tb, idx := s.Build(\"CREATE\"), add.I\n\t\tif idx.Unique {\n\t\t\tb.P(\"UNIQUE\")\n\t\t}\n\t\tb.P(\"INDEX\")\n\t\tif sqlx.Has(add.Extra, &Concurrently{}) {\n\t\t\tb.P(\"CONCURRENTLY\")\n\t\t}\n\t\tif idx.Name != \"\" {\n\t\t\tb.Ident(idx.Name)\n\t\t}\n\t\tb.P(\"ON\").Table(t)\n\t\tif err := s.index(b, idx); err != nil {\n\t\t\treturn err\n\t\t}\n\t\ts.append(&migrate.Change{\n\t\t\tCmd:     b.String(),\n\t\t\tSource:  src,\n\t\t\tComment: fmt.Sprintf(\"create index %q to table: %q\", idx.Name, t.Name),\n\t\t\tReverse: func() string {\n\t\t\t\tb := s.Build(\"DROP INDEX\")\n\t\t\t\tif sqlx.Has(add.Extra, &Concurrently{}) {\n\t\t\t\t\tb.P(\"CONCURRENTLY\")\n\t\t\t\t}\n\t\t\t\t// Unlike MySQL, the DROP command is not attached to ALTER TABLE.\n\t\t\t\t// Therefore, we print indexes with their qualified name, because\n\t\t\t\t// the connection that executes the statements may not be attached\n\t\t\t\t// to this schema.\n\t\t\t\tif t.Schema != nil {\n\t\t\t\t\tb.WriteString(s.schemaPrefix(t.Schema))\n\t\t\t\t}\n\t\t\t\tb.Ident(idx.Name)\n\t\t\t\treturn b.String()\n\t\t\t}(),\n\t\t})\n\t}\n\treturn nil\n}\n\nfunc (s *state) column(b *sqlx.Builder, c *schema.Column) error {\n\tf, err := s.formatType(c.Type.Type)\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.Ident(c.Name).P(f)\n\tif !c.Type.Null {\n\t\tb.P(\"NOT\")\n\t} else if t, ok := c.Type.Type.(*SerialType); ok {\n\t\treturn fmt.Errorf(\"NOT NULL constraint is required for %s column %q\", t.T, c.Name)\n\t}\n\tb.P(\"NULL\")\n\ts.columnDefault(b, c)\n\tif collate := (schema.Collation{}); sqlx.Has(c.Attrs, &collate) {\n\t\tb.P(\"COLLATE\").Ident(collate.V)\n\t}\n\tswitch hasI, hasX := sqlx.Has(c.Attrs, &Identity{}), sqlx.Has(c.Attrs, &schema.GeneratedExpr{}); {\n\tcase hasI && hasX:\n\t\treturn fmt.Errorf(\"both identity and generation expression specified for column %q\", c.Name)\n\tcase hasI:\n\t\tid, _ := identity(c.Attrs)\n\t\tb.P(\"GENERATED\", id.Generation, \"AS IDENTITY\")\n\t\tif id.Sequence.Start != defaultSeqStart || id.Sequence.Increment != defaultSeqIncrement {\n\t\t\tb.Wrap(func(b *sqlx.Builder) {\n\t\t\t\tif id.Sequence.Start != defaultSeqStart {\n\t\t\t\t\tb.P(\"START WITH\", strconv.FormatInt(id.Sequence.Start, 10))\n\t\t\t\t}\n\t\t\t\tif id.Sequence.Increment != defaultSeqIncrement {\n\t\t\t\t\tb.P(\"INCREMENT BY\", strconv.FormatInt(id.Sequence.Increment, 10))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\tcase hasX:\n\t\tx := &schema.GeneratedExpr{}\n\t\tsqlx.Has(c.Attrs, x)\n\t\tb.P(\"GENERATED ALWAYS AS\", sqlx.MayWrap(x.Expr), \"STORED\")\n\t}\n\treturn nil\n}\n\n// columnDefault writes the default value of column to the builder.\nfunc (s *state) columnDefault(b *sqlx.Builder, c *schema.Column) {\n\tif c.Default != nil {\n\t\ts.formatDefault(b, c.Type.Type, c.Default)\n\t}\n}\n\n// formatDefault writes the default value of column to the builder.\nfunc (s *state) formatDefault(b *sqlx.Builder, t schema.Type, x schema.Expr) {\n\tswitch x := x.(type) {\n\tcase *schema.Literal:\n\t\tv := x.V\n\t\tswitch t.(type) {\n\t\tcase *schema.BoolType, *schema.DecimalType, *schema.IntegerType, *schema.FloatType:\n\t\tdefault:\n\t\t\tv = quote(v)\n\t\t}\n\t\tb.P(\"DEFAULT\", v)\n\tcase *schema.RawExpr:\n\t\t// Ignore identity functions added by the Differ.\n\t\tif _, ok := t.(*SerialType); !ok {\n\t\t\tb.P(\"DEFAULT\", x.X)\n\t\t}\n\t}\n}\n\nfunc (s *state) indexParts(b *sqlx.Builder, idx *schema.Index) (err error) {\n\tb.Wrap(func(b *sqlx.Builder) {\n\t\terr = b.MapCommaErr(idx.Parts, func(i int, b *sqlx.Builder) error {\n\t\t\tswitch part := idx.Parts[i]; {\n\t\t\tcase part.C != nil:\n\t\t\t\tb.Ident(part.C.Name)\n\t\t\tcase part.X != nil:\n\t\t\t\tb.WriteString(sqlx.MayWrap(part.X.(*schema.RawExpr).X))\n\t\t\t}\n\t\t\treturn s.partAttrs(b, idx, idx.Parts[i])\n\t\t})\n\t})\n\treturn\n}\n\nfunc (s *state) partAttrs(b *sqlx.Builder, idx *schema.Index, p *schema.IndexPart) error {\n\tif c := (schema.Collation{}); sqlx.Has(p.Attrs, &c) {\n\t\tb.P(\"COLLATE\").Ident(c.V)\n\t}\n\tif op := (IndexOpClass{}); sqlx.Has(p.Attrs, &op) {\n\t\td, err := op.DefaultFor(idx, p)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !d {\n\t\t\tb.P(op.String())\n\t\t}\n\t}\n\tif p.Desc {\n\t\tb.P(\"DESC\")\n\t}\n\tif prop := (&IndexColumnProperty{}); sqlx.Has(p.Attrs, prop) {\n\t\tswitch {\n\t\t// Defaults when DESC is specified.\n\t\tcase p.Desc && prop.NullsFirst:\n\t\tcase p.Desc && prop.NullsLast:\n\t\t\tb.P(\"NULLS LAST\")\n\t\t// Defaults when DESC is not specified.\n\t\tcase !p.Desc && prop.NullsLast:\n\t\tcase !p.Desc && prop.NullsFirst:\n\t\t\tb.P(\"NULLS FIRST\")\n\t\t}\n\t}\n\tif _, isE := excludeConst(idx.Attrs); isE {\n\t\tswitch op := (&Operator{}); {\n\t\tcase !sqlx.Has(p.Attrs, op):\n\t\t\treturn fmt.Errorf(\"missing operator for exclude constraint %q\", idx.Name)\n\t\tcase op.Name == \"\":\n\t\t\treturn fmt.Errorf(\"empty operator for exclude constraint %q\", idx.Name)\n\t\tdefault:\n\t\t\tb.P(\"WITH\", op.Name)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (s *state) index(b *sqlx.Builder, idx *schema.Index) error {\n\t// Avoid appending the default method.\n\tif t := (IndexType{}); sqlx.Has(idx.Attrs, &t) && strings.ToUpper(t.T) != IndexTypeBTree {\n\t\tb.P(\"USING\", t.T)\n\t}\n\tif err := s.indexParts(b, idx); err != nil {\n\t\treturn err\n\t}\n\tif c := (IndexInclude{}); sqlx.Has(idx.Attrs, &c) {\n\t\tb.P(\"INCLUDE\")\n\t\tb.Wrap(func(b *sqlx.Builder) {\n\t\t\tb.MapComma(c.Columns, func(i int, b *sqlx.Builder) {\n\t\t\t\tb.Ident(c.Columns[i].Name)\n\t\t\t})\n\t\t})\n\t}\n\t// Handled separately by the UNIQUE builder.\n\tif _, ok := uniqueConst(idx.Attrs); !ok {\n\t\tnullsNotDistinct(b, idx)\n\t}\n\tif p, ok := indexStorageParams(idx.Attrs); ok {\n\t\tb.P(\"WITH\")\n\t\tb.Wrap(func(b *sqlx.Builder) {\n\t\t\tvar parts []string\n\t\t\tif p.AutoSummarize {\n\t\t\t\tparts = append(parts, \"autosummarize = true\")\n\t\t\t}\n\t\t\tif p.PagesPerRange != 0 && p.PagesPerRange != defaultPagesPerRange {\n\t\t\t\tparts = append(parts, fmt.Sprintf(\"pages_per_range = %d\", p.PagesPerRange))\n\t\t\t}\n\t\t\tb.WriteString(strings.Join(parts, \", \"))\n\t\t})\n\t}\n\tif p := (IndexPredicate{}); sqlx.Has(idx.Attrs, &p) {\n\t\tb.P(\"WHERE\").P(p.P)\n\t}\n\treturn nil\n}\n\nfunc (s *state) fks(b *sqlx.Builder, fks ...*schema.ForeignKey) {\n\tb.MapIndent(fks, func(i int, b *sqlx.Builder) {\n\t\tfk := fks[i]\n\t\tif fk.Symbol != \"\" {\n\t\t\tb.P(\"CONSTRAINT\").Ident(fk.Symbol)\n\t\t}\n\t\tb.P(\"FOREIGN KEY\")\n\t\tb.Wrap(func(b *sqlx.Builder) {\n\t\t\tb.MapComma(fk.Columns, func(i int, b *sqlx.Builder) {\n\t\t\t\tb.Ident(fk.Columns[i].Name)\n\t\t\t})\n\t\t})\n\t\tb.P(\"REFERENCES\").Table(fk.RefTable)\n\t\tb.Wrap(func(b *sqlx.Builder) {\n\t\t\tb.MapComma(fk.RefColumns, func(i int, b *sqlx.Builder) {\n\t\t\t\tb.Ident(fk.RefColumns[i].Name)\n\t\t\t})\n\t\t})\n\t\tif fk.OnUpdate != \"\" {\n\t\t\tb.P(\"ON UPDATE\", string(fk.OnUpdate))\n\t\t}\n\t\tif fk.OnDelete != \"\" {\n\t\t\tb.P(\"ON DELETE\", string(fk.OnDelete))\n\t\t}\n\t})\n}\n\nfunc (s *state) constraint(b *sqlx.Builder, idx *schema.Index) error {\n\tif _, isU := uniqueConst(idx.Attrs); isU {\n\t\treturn s.unique(b, idx)\n\t}\n\tif _, isE := excludeConst(idx.Attrs); isE {\n\t\treturn s.exclude(b, idx)\n\t}\n\treturn fmt.Errorf(\"unexpected constraint type for index %q\", idx.Name)\n}\n\nfunc (s *state) unique(b *sqlx.Builder, idx *schema.Index) error {\n\tc, ok := uniqueConst(idx.Attrs)\n\tif !ok {\n\t\treturn fmt.Errorf(\"index %q is not a unique constraint\", idx.Name)\n\t}\n\tname := c.N\n\tif name == \"\" {\n\t\tname = idx.Name\n\t}\n\tb.P(\"CONSTRAINT\").Ident(name).P(\"UNIQUE\")\n\t// In UNIQUE constraints, the NULLS [NOT] DISTINCT\n\t// clause is written before the index parts.\n\tnullsNotDistinct(b, idx)\n\treturn s.index(b, idx)\n}\n\nfunc (s *state) exclude(b *sqlx.Builder, idx *schema.Index) error {\n\tc, ok := excludeConst(idx.Attrs)\n\tif !ok {\n\t\treturn fmt.Errorf(\"index %q is not an exclude constraint\", idx.Name)\n\t}\n\tname := c.N\n\tif name == \"\" {\n\t\tname = idx.Name\n\t}\n\tb.P(\"CONSTRAINT\").Ident(name).P(\"EXCLUDE\")\n\treturn s.index(b, idx)\n}\n\nfunc (s *state) append(c ...*migrate.Change) {\n\ts.Changes = append(s.Changes, c...)\n}\n\n// Build instantiates a new builder and writes the given phrase to it.\nfunc (s *state) Build(phrases ...string) *sqlx.Builder {\n\treturn (*Driver).StmtBuilder(nil, s.PlanOptions).\n\t\tP(phrases...)\n}\n\n// skipAutoChanges filters unnecessary changes that are automatically\n// happened by the database when ALTER TABLE is executed.\nfunc skipAutoChanges(changes []schema.Change) []schema.Change {\n\tvar (\n\t\tdropC   = make(map[string]bool)\n\t\tplanned = make([]schema.Change, 0, len(changes))\n\t)\n\tfor _, c := range changes {\n\t\tif c, ok := c.(*schema.DropColumn); ok {\n\t\t\tdropC[c.C.Name] = true\n\t\t}\n\t}\nsearch:\n\tfor _, c := range changes {\n\t\tswitch c := c.(type) {\n\t\t// Indexes involving the column are automatically dropped\n\t\t// with it. This is true for multi-columns indexes as well.\n\t\t// See https://www.postgresql.org/docs/current/sql-altertable.html\n\t\tcase *schema.DropIndex:\n\t\t\tfor _, p := range c.I.Parts {\n\t\t\t\tif p.C != nil && dropC[p.C.Name] {\n\t\t\t\t\tcontinue search\n\t\t\t\t}\n\t\t\t}\n\t\t// Simple case for skipping constraint dropping,\n\t\t// if the child table columns were dropped.\n\t\tcase *schema.DropForeignKey:\n\t\t\tfor _, c := range c.F.Columns {\n\t\t\t\tif dropC[c.Name] {\n\t\t\t\t\tcontinue search\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tplanned = append(planned, c)\n\t}\n\treturn planned\n}\n\n// commentChange extracts the information for modifying a comment from the given change.\nfunc commentChange(c schema.Change) (from, to string, err error) {\n\tswitch c := c.(type) {\n\tcase *schema.AddAttr:\n\t\ttoC, ok := c.A.(*schema.Comment)\n\t\tif ok {\n\t\t\tto = toC.Text\n\t\t\treturn\n\t\t}\n\t\terr = fmt.Errorf(\"unexpected AddAttr.(%T) for comment change\", c.A)\n\tcase *schema.ModifyAttr:\n\t\tfromC, ok1 := c.From.(*schema.Comment)\n\t\ttoC, ok2 := c.To.(*schema.Comment)\n\t\tif ok1 && ok2 {\n\t\t\tfrom, to = fromC.Text, toC.Text\n\t\t\treturn\n\t\t}\n\t\terr = fmt.Errorf(\"unsupported ModifyAttr(%T, %T) change\", c.From, c.To)\n\tdefault:\n\t\terr = fmt.Errorf(\"unexpected change %T\", c)\n\t}\n\treturn\n}\n\n// checks writes the CHECK constraint to the builder.\nfunc check(b *sqlx.Builder, c *schema.Check) {\n\tif c.Name != \"\" {\n\t\tb.P(\"CONSTRAINT\").Ident(c.Name)\n\t}\n\tb.P(\"CHECK\", sqlx.MayWrap(c.Expr))\n\tif sqlx.Has(c.Attrs, &NoInherit{}) {\n\t\tb.P(\"NO INHERIT\")\n\t}\n}\n\nfunc quote(s string) string {\n\tif sqlx.IsQuoted(s, '\\'') {\n\t\treturn s\n\t}\n\treturn \"'\" + strings.ReplaceAll(s, \"'\", \"''\") + \"'\"\n}\n\nfunc (s *state) createDropEnum(e *schema.EnumType) (string, string) {\n\tname := s.enumIdent(e)\n\treturn s.Build(\"CREATE TYPE\").\n\t\t\tP(name, \"AS ENUM\").\n\t\t\tWrap(func(b *sqlx.Builder) {\n\t\t\t\tb.MapComma(e.Values, func(i int, b *sqlx.Builder) {\n\t\t\t\t\tb.WriteString(quote(e.Values[i]))\n\t\t\t\t})\n\t\t\t}).\n\t\t\tString(),\n\t\ts.Build(\"DROP TYPE\").P(name).String()\n}\n\nfunc (s *state) enumIdent(e *schema.EnumType) string {\n\treturn s.typeIdent(e.Schema, e.T)\n}\n\nfunc (s *state) domainIdent(d *DomainType) string {\n\treturn s.typeIdent(d.Schema, d.T)\n}\n\nfunc (s *state) compositeIdent(c *CompositeType) string {\n\treturn s.typeIdent(c.Schema, c.T)\n}\n\nfunc (s *state) typeIdent(ns *schema.Schema, name string) string {\n\tswitch {\n\t// In case the plan uses a specific schema qualifier.\n\tcase s.SchemaQualifier != nil:\n\t\tif *s.SchemaQualifier != \"\" {\n\t\t\treturn fmt.Sprintf(\"%q.%q\", *s.SchemaQualifier, name)\n\t\t}\n\tcase ns != nil && ns.Name != \"\":\n\t\treturn fmt.Sprintf(\"%q.%q\", ns.Name, name)\n\t}\n\treturn strconv.Quote(name)\n}\n\n// schemaPrefix returns the schema prefix based on the planner config.\nfunc (s *state) schemaPrefix(ns *schema.Schema) string {\n\tswitch {\n\tcase s.SchemaQualifier != nil:\n\t\t// In case the qualifier is empty, ignore.\n\t\tif *s.SchemaQualifier != \"\" {\n\t\t\treturn fmt.Sprintf(\"%q.\", *s.SchemaQualifier)\n\t\t}\n\tcase ns != nil && ns.Name != \"\":\n\t\treturn fmt.Sprintf(\"%q.\", ns.Name)\n\t}\n\treturn \"\"\n}\n\n// formatType formats the type but takes into account the qualifier.\nfunc (s *state) formatType(t schema.Type) (string, error) {\n\tswitch t := t.(type) {\n\tcase *schema.EnumType:\n\t\treturn s.enumIdent(t), nil\n\tcase *DomainType:\n\t\treturn s.domainIdent(t), nil\n\tcase *CompositeType:\n\t\treturn s.compositeIdent(t), nil\n\tcase *ArrayType:\n\t\tswitch t := t.Type.(type) {\n\t\tcase *schema.EnumType:\n\t\t\treturn s.enumIdent(t) + \"[]\", nil\n\t\tcase *DomainType:\n\t\t\treturn s.domainIdent(t) + \"[]\", nil\n\t\tcase *CompositeType:\n\t\t\treturn s.compositeIdent(t) + \"[]\", nil\n\t\t}\n\t}\n\treturn FormatType(t)\n}\n\nfunc pkName(t *schema.Table, pk *schema.Index) string {\n\tif pk.Name != \"\" {\n\t\treturn pk.Name\n\t}\n\t// The default naming for primary-key constraints is <Table>_pkey.\n\t// See: the ChooseIndexName function in PostgreSQL for more reference.\n\treturn t.Name + \"_pkey\"\n}\n\n// dropConst indicates if the given change is a constraint drop.\nfunc dropConst(c schema.Change) bool {\n\tswitch c.(type) {\n\tcase *schema.DropIndex, *schema.DropPrimaryKey, *schema.DropCheck, *schema.DropForeignKey:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// nullsNotDistinct handles the NULLS [NOT] DISTINCT clause for indexes.\nfunc nullsNotDistinct(b *sqlx.Builder, idx *schema.Index) {\n\t// Avoid appending the default behavior, which NULL values are distinct.\n\tif n := (IndexNullsDistinct{}); sqlx.Has(idx.Attrs, &n) && !n.V {\n\t\tb.P(\"NULLS NOT DISTINCT\")\n\t}\n}\n"
  },
  {
    "path": "sql/postgres/migrate_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/internal/sqltest\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestPlanChanges(t *testing.T) {\n\ttests := []struct {\n\t\tchanges  []schema.Change\n\t\toptions  []migrate.PlanOption\n\t\tmock     func(mock)\n\t\twantPlan *migrate.Plan\n\t\twantErr  bool\n\t}{\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddSchema{S: schema.New(\"public\").SetComment(\"public schema\")},\n\t\t\t\t&schema.AddSchema{S: schema.New(\"test\"), Extra: []schema.Clause{&schema.IfNotExists{}}},\n\t\t\t\t&schema.DropSchema{S: schema.New(\"test\"), Extra: []schema.Clause{&schema.IfExists{}}},\n\t\t\t\t&schema.DropSchema{S: schema.New(\"test\"), Extra: []schema.Clause{}},\n\t\t\t\t&schema.ModifySchema{S: schema.New(\"modify1\").SetComment(\"comment\"), Changes: schema.Changes{&schema.AddAttr{A: &schema.Comment{Text: \"comment\"}}}},\n\t\t\t\t&schema.ModifySchema{S: schema.New(\"modify2\").SetComment(\"comment\"), Changes: schema.Changes{&schema.ModifyAttr{From: &schema.Comment{Text: \"old\"}, To: &schema.Comment{Text: \"new\"}}}},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    false,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE SCHEMA IF NOT EXISTS \"public\"`,\n\t\t\t\t\t\tReverse: `DROP SCHEMA \"public\" CASCADE`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `COMMENT ON SCHEMA \"public\" IS 'public schema'`,\n\t\t\t\t\t\tReverse: `COMMENT ON SCHEMA \"public\" IS ''`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE SCHEMA IF NOT EXISTS \"test\"`,\n\t\t\t\t\t\tReverse: `DROP SCHEMA \"test\" CASCADE`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd: `DROP SCHEMA IF EXISTS \"test\" CASCADE`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd: `DROP SCHEMA \"test\" CASCADE`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `COMMENT ON SCHEMA \"modify1\" IS 'comment'`,\n\t\t\t\t\t\tReverse: `COMMENT ON SCHEMA \"modify1\" IS ''`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `COMMENT ON SCHEMA \"modify2\" IS 'new'`,\n\t\t\t\t\t\tReverse: `COMMENT ON SCHEMA \"modify2\" IS 'old'`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\tpets := &schema.Table{\n\t\t\t\t\t\tName: \"pets\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t{Name: \"user_id\",\n\t\t\t\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\t\t\t\tType: &schema.IntegerType{T: \"bigint\"},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\tfk := &schema.ForeignKey{\n\t\t\t\t\t\tSymbol:     \"pets_user_id_fkey\",\n\t\t\t\t\t\tTable:      pets,\n\t\t\t\t\t\tOnUpdate:   schema.NoAction,\n\t\t\t\t\t\tOnDelete:   schema.Cascade,\n\t\t\t\t\t\tRefTable:   users,\n\t\t\t\t\t\tColumns:    []*schema.Column{pets.Columns[1]},\n\t\t\t\t\t\tRefColumns: []*schema.Column{users.Columns[0]},\n\t\t\t\t\t}\n\t\t\t\t\tfk1 := *fk\n\t\t\t\t\tfk1.Symbol += \"1\"\n\t\t\t\t\tpets.ForeignKeys = []*schema.ForeignKey{fk}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: pets,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropForeignKey{\n\t\t\t\t\t\t\t\tF: fk,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.DropForeignKey{\n\t\t\t\t\t\t\t\tF: &fk1,\n\t\t\t\t\t\t\t\tExtra: []schema.Clause{\n\t\t\t\t\t\t\t\t\t&schema.IfExists{},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"pets\" DROP CONSTRAINT \"pets_user_id_fkey\", DROP CONSTRAINT IF EXISTS \"pets_user_id_fkey1\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"pets\" ADD CONSTRAINT \"pets_user_id_fkey1\" FOREIGN KEY (\"user_id\") REFERENCES \"users\" (\"id\") ON UPDATE NO ACTION ON DELETE CASCADE, ADD CONSTRAINT \"pets_user_id_fkey\" FOREIGN KEY (\"user_id\") REFERENCES \"users\" (\"id\") ON UPDATE NO ACTION ON DELETE CASCADE`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t{Name: \"name\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(255)\"}}}},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropIndex{\n\t\t\t\t\t\t\t\tI: schema.NewIndex(\"name_index\").\n\t\t\t\t\t\t\t\t\tAddParts(schema.NewColumnPart(schema.NewColumn(\"name\"))),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP INDEX \"name_index\"`,\n\t\t\t\t\t\tReverse: `CREATE INDEX \"name_index\" ON \"users\" (\"name\")`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t{Name: \"nickname\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(255)\"}}}},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropIndex{\n\t\t\t\t\t\t\t\tI: schema.NewUniqueIndex(\"unique_nickname\").\n\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"nickname\")).\n\t\t\t\t\t\t\t\t\tAddAttrs(&Constraint{T: \"u\"}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"users\" DROP CONSTRAINT \"unique_nickname\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"users\" ADD CONSTRAINT \"unique_nickname\" UNIQUE (\"nickname\")`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddSchema{S: &schema.Schema{Name: \"test\"}},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges:       []*migrate.Change{{Cmd: `CREATE SCHEMA \"test\"`, Reverse: `DROP SCHEMA \"test\" CASCADE`}}},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropSchema{S: &schema.Schema{Name: \"atlas\"}},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges:       []*migrate.Change{{Cmd: `DROP SCHEMA \"atlas\" CASCADE`}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddObject{\n\t\t\t\t\tO: &schema.EnumType{\n\t\t\t\t\t\tT:      \"direction\",\n\t\t\t\t\t\tValues: []string{\"NORTH\", \"SOUTH\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{&Identity{}, &schema.Comment{}}},\n\t\t\t\t\t\t\t{Name: \"text\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Null: true}},\n\t\t\t\t\t\t\t{Name: \"directions\", Type: &schema.ColumnType{Type: &ArrayType{T: \"direction[]\", Type: &schema.EnumType{T: \"direction\", Values: []string{\"NORTH\", \"SOUTH\"}, Schema: schema.New(\"public\")}}}},\n\t\t\t\t\t\t\t{Name: \"states\", Type: &schema.ColumnType{Type: &ArrayType{T: \"state[]\", Type: &schema.EnumType{T: \"state\", Values: []string{\"ON\", \"OFF\"}}}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Comment{},\n\t\t\t\t\t\t\t&schema.Check{Name: \"id_nonzero\", Expr: `(\"id\" > 0)`},\n\t\t\t\t\t\t\t&schema.Check{Name: \"text_len\", Expr: `(length(\"text\") > 0)`, Attrs: []schema.Attr{&NoInherit{}}},\n\t\t\t\t\t\t\t&schema.Check{Name: \"a_in_b\", Expr: `(a) in (b)`},\n\t\t\t\t\t\t\t&Partition{T: \"HASH\", Parts: []*PartitionPart{{C: schema.NewColumn(\"text\")}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tmock: func(m mock) {\n\t\t\t\tm.ExpectQuery(sqltest.Escape(\"SELECT * FROM pg_type t JOIN pg_namespace n on t.typnamespace = n.oid WHERE t.typname = $1 AND t.typtype = 'e' AND n.nspname = $2\")).\n\t\t\t\t\tWithArgs(\"direction\", \"public\").\n\t\t\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"name\"}))\n\t\t\t\tm.ExpectQuery(sqltest.Escape(\"SELECT * FROM pg_type t JOIN pg_namespace n on t.typnamespace = n.oid WHERE t.typname = $1 AND t.typtype = 'e'\")).\n\t\t\t\t\tWithArgs(\"state\").\n\t\t\t\t\tWillReturnRows(sqlmock.NewRows([]string{\"name\"}).AddRow(\"state\"))\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `CREATE TYPE \"public\".\"direction\" AS ENUM ('NORTH', 'SOUTH')`, Reverse: `DROP TYPE \"public\".\"direction\"`},\n\t\t\t\t\t{Cmd: `CREATE TABLE \"posts\" (\"id\" integer NOT NULL GENERATED BY DEFAULT AS IDENTITY, \"text\" text NULL, \"directions\" \"public\".\"direction\"[] NOT NULL, \"states\" \"state\"[] NOT NULL, CONSTRAINT \"id_nonzero\" CHECK (\"id\" > 0), CONSTRAINT \"text_len\" CHECK (length(\"text\") > 0) NO INHERIT, CONSTRAINT \"a_in_b\" CHECK ((a) in (b))) PARTITION BY HASH (\"text\")`, Reverse: `DROP TABLE \"posts\"`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{&Identity{Sequence: &Sequence{Start: 1024}}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges:       []*migrate.Change{{Cmd: `CREATE TABLE \"posts\" (\"id\" integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1024))`, Reverse: `DROP TABLE \"posts\"`}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}},\n\t\t\t\t\t\t\t{Name: \"nid\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{&schema.GeneratedExpr{Expr: \"id+1\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE TABLE \"posts\" (\"id\" integer NOT NULL, \"nid\" integer NOT NULL GENERATED ALWAYS AS (id+1) STORED)`,\n\t\t\t\t\t\tReverse: `DROP TABLE \"posts\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\").\n\t\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"id+1\"}),\n\t\t\t\t\t\t),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tChange: schema.ChangeGenerated,\n\t\t\t\t\t\t\tFrom: schema.NewIntColumn(\"c1\", \"int\").\n\t\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"id+1\"}),\n\t\t\t\t\t\t\tTo: schema.NewIntColumn(\"c1\", \"int\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    false,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd: `ALTER TABLE \"posts\" ALTER COLUMN \"c1\" DROP EXPRESSION`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{&Identity{Sequence: &Sequence{Increment: 2}}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges:       []*migrate.Change{{Cmd: `CREATE TABLE \"posts\" (\"id\" integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (INCREMENT BY 2))`, Reverse: `DROP TABLE \"posts\"`}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{&Identity{Sequence: &Sequence{Start: 100, Increment: 2}}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges:       []*migrate.Change{{Cmd: `CREATE TABLE \"posts\" (\"id\" integer NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 100 INCREMENT BY 2))`, Reverse: `DROP TABLE \"posts\"`}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropTable{T: schema.NewTable(\"posts\").AddColumns(schema.NewIntColumn(\"id\", \"int\"))},\n\t\t\t\t&schema.DropTable{T: schema.NewTable(\"users\").AddColumns(schema.NewIntColumn(\"id\", \"int\")), Extra: []schema.Clause{&Cascade{}}},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP TABLE \"posts\"`,\n\t\t\t\t\t\tReverse: `CREATE TABLE \"posts\" (\"id\" integer NOT NULL)`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP TABLE \"users\" CASCADE`,\n\t\t\t\t\t\tReverse: `CREATE TABLE \"users\" (\"id\" integer NOT NULL)`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropTable{T: schema.NewTable(\"logs\").\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewColumn(\"status\").SetType(&schema.EnumType{T: \"status\", Values: []string{\"on\", \"off\"}, Schema: schema.New(\"public\")}),\n\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t\t&schema.DropObject{O: &schema.EnumType{T: \"status\", Values: []string{\"on\", \"off\"}, Schema: schema.New(\"public\")}},\n\t\t\t\t&schema.DropObject{O: &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\"}, Schema: schema.New(\"public\")}},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP TABLE \"logs\"`,\n\t\t\t\t\t\tReverse: `CREATE TABLE \"logs\" (\"status\" \"public\".\"status\" NOT NULL)`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP TYPE \"public\".\"status\"`,\n\t\t\t\t\t\tReverse: `CREATE TYPE \"public\".\"status\" AS ENUM ('on', 'off')`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP TYPE \"public\".\"state\"`,\n\t\t\t\t\t\tReverse: `CREATE TYPE \"public\".\"state\" AS ENUM ('on', 'off')`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropTable{\n\t\t\t\t\tT: func() *schema.Table {\n\t\t\t\t\t\tid := schema.NewIntColumn(\"id\", \"int\")\n\t\t\t\t\t\treturn schema.NewTable(\"posts\").\n\t\t\t\t\t\t\tSetComment(\"a8m's posts\").\n\t\t\t\t\t\t\tAddColumns(id).\n\t\t\t\t\t\t\tAddIndexes(\n\t\t\t\t\t\t\t\tschema.NewIndex(\"idx\").AddColumns(id).SetComment(\"a8m's index\"),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t}(),\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd: `DROP TABLE \"posts\"`,\n\t\t\t\t\t\tReverse: []string{\n\t\t\t\t\t\t\t`CREATE TABLE \"posts\" (\"id\" integer NOT NULL)`,\n\t\t\t\t\t\t\t`CREATE INDEX \"idx\" ON \"posts\" (\"id\")`,\n\t\t\t\t\t\t\t`COMMENT ON TABLE \"posts\" IS 'a8m''s posts'`,\n\t\t\t\t\t\t\t`COMMENT ON INDEX \"idx\" IS 'a8m''s index'`,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Qualified DROP TABLE plan.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropTable{\n\t\t\t\t\tT: func() *schema.Table {\n\t\t\t\t\t\tid := schema.NewIntColumn(\"id\", \"int\")\n\t\t\t\t\t\treturn schema.NewTable(\"posts\").\n\t\t\t\t\t\t\tSetSchema(schema.New(\"private\")).\n\t\t\t\t\t\t\tSetComment(\"a8m's posts\").\n\t\t\t\t\t\t\tAddColumns(id).\n\t\t\t\t\t\t\tAddIndexes(\n\t\t\t\t\t\t\t\tschema.NewIndex(\"idx\").AddColumns(id).SetComment(\"a8m's index\"),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t}(),\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd: `DROP TABLE \"private\".\"posts\"`,\n\t\t\t\t\t\tReverse: []string{\n\t\t\t\t\t\t\t`CREATE TABLE \"private\".\"posts\" (\"id\" integer NOT NULL)`,\n\t\t\t\t\t\t\t`CREATE INDEX \"idx\" ON \"private\".\"posts\" (\"id\")`,\n\t\t\t\t\t\t\t`COMMENT ON TABLE \"private\".\"posts\" IS 'a8m''s posts'`,\n\t\t\t\t\t\t\t`COMMENT ON INDEX \"private\".\"idx\" IS 'a8m''s index'`,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Drop a primary key.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t\t)\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropPrimaryKey{\n\t\t\t\t\t\t\t\tP: schema.NewPrimaryKey(users.Columns...),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"test\".\"users\" DROP CONSTRAINT \"users_pkey\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"test\".\"users\" ADD PRIMARY KEY (\"id\")`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Add a primary key.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t)\n\t\t\t\t\tusers.SetPrimaryKey(schema.NewPrimaryKey(users.Columns...))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddPrimaryKey{\n\t\t\t\t\t\t\t\tP: users.PrimaryKey,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"test\".\"users\" ADD PRIMARY KEY (\"id\")`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"test\".\"users\" DROP CONSTRAINT \"users_pkey\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Add a named unique constraint using index.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t)\n\t\t\t\t\tusers.SetPrimaryKey(schema.NewPrimaryKey(users.Columns...))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&AddUniqueConstraint{\n\t\t\t\t\t\t\t\tName:  \"users_unique\",\n\t\t\t\t\t\t\t\tUsing: schema.NewUniqueIndex(\"boring\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"test\".\"users\" ADD CONSTRAINT \"users_unique\" UNIQUE USING INDEX \"boring\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"test\".\"users\" DROP CONSTRAINT \"users_unique\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Add an unnamed unique constraint using index.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t)\n\t\t\t\t\tusers.SetPrimaryKey(schema.NewPrimaryKey(users.Columns...))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&AddUniqueConstraint{\n\t\t\t\t\t\t\t\tUsing: schema.NewUniqueIndex(\"boring\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"test\".\"users\" ADD UNIQUE USING INDEX \"boring\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"test\".\"users\" DROP CONSTRAINT \"boring\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Add a named primary key constraint using index.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t)\n\t\t\t\t\tusers.SetPrimaryKey(schema.NewPrimaryKey(users.Columns...))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&AddPKConstraint{\n\t\t\t\t\t\t\t\tName:  \"users_pkey\",\n\t\t\t\t\t\t\t\tUsing: schema.NewUniqueIndex(\"users_pkey\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"test\".\"users\" ADD CONSTRAINT \"users_pkey\" PRIMARY KEY USING INDEX \"users_pkey\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"test\".\"users\" DROP CONSTRAINT \"users_pkey\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Add an unnamed primary key constraint using index.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t)\n\t\t\t\t\tusers.SetPrimaryKey(schema.NewPrimaryKey(users.Columns...))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&AddPKConstraint{\n\t\t\t\t\t\t\t\tUsing: schema.NewUniqueIndex(\"users_pkey\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"test\".\"users\" ADD PRIMARY KEY USING INDEX \"users_pkey\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"test\".\"users\" DROP CONSTRAINT \"users_pkey\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Modify a primary key.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tdropC, addC := schema.NewStringColumn(\"email\", \"text\"), schema.NewStringColumn(\"name\", \"text\")\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewStringColumn(\"id\", \"text\"), addC, schema.NewStringColumn(\"last\", \"text\"))\n\t\t\t\t\tusers.SetPrimaryKey(schema.NewPrimaryKey(addC))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropColumn{C: dropC},\n\t\t\t\t\t\t\t&schema.AddColumn{C: addC},\n\t\t\t\t\t\t\t&schema.ModifyPrimaryKey{\n\t\t\t\t\t\t\t\tFrom: schema.NewPrimaryKey(dropC).\n\t\t\t\t\t\t\t\t\tAddAttrs(&IndexInclude{Columns: users.Columns[2:]}),\n\t\t\t\t\t\t\t\tTo: users.PrimaryKey,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"users\" DROP CONSTRAINT \"users_pkey\", DROP COLUMN \"email\", ADD COLUMN \"name\" text NOT NULL, ADD PRIMARY KEY (\"name\")`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"users\" DROP CONSTRAINT \"users_pkey\", DROP COLUMN \"name\", ADD COLUMN \"email\" text NOT NULL, ADD PRIMARY KEY (\"email\") INCLUDE (\"last\")`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: &schema.Column{Name: \"name\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar\", Size: 255}}, Attrs: []schema.Attr{&schema.Comment{Text: \"foo\"}}, Default: &schema.Literal{V: \"'logged_in'\"}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: &schema.Column{Name: \"last\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar\", Size: 255}}, Attrs: []schema.Attr{&schema.Comment{Text: \"bar\"}}, Default: &schema.RawExpr{X: \"'logged_in'\"}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tName: \"id_key\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0], Desc: true},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t\t&schema.Comment{Text: \"comment\"},\n\t\t\t\t\t\t\t\t\t\t&IndexPredicate{P: \"success\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tName: \"id_brin\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0], Desc: true},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t\t&IndexType{T: IndexTypeBRIN},\n\t\t\t\t\t\t\t\t\t\t&IndexStorageParams{PagesPerRange: 2},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddCheck{\n\t\t\t\t\t\t\t\tC: &schema.Check{Name: \"name_not_empty\", Expr: `(\"name\" <> '')`},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddCheck{\n\t\t\t\t\t\t\t\tC:     &schema.Check{Name: \"positive_id\", Expr: `(\"id\" > 0)`},\n\t\t\t\t\t\t\t\tExtra: []schema.Clause{&NotValid{}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.DropCheck{\n\t\t\t\t\t\t\t\tC: &schema.Check{Name: \"id_nonzero\", Expr: `(\"id\" <> 0)`},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyCheck{\n\t\t\t\t\t\t\t\tFrom: &schema.Check{Name: \"id_iseven\", Expr: `(\"id\" % 2 = 0)`},\n\t\t\t\t\t\t\t\tTo:   &schema.Check{Name: \"id_iseven\", Expr: `((\"id\") % 2 = 0)`},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tName: \"include_key\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0]},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t\t&IndexInclude{Columns: []*schema.Column{schema.NewColumn(\"a\"), schema.NewColumn(\"b\")}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tName: \"add_con\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0]},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tExtra: []schema.Clause{\n\t\t\t\t\t\t\t\t\t&Concurrently{},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.DropIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tName: \"drop_con\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0]},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tExtra: []schema.Clause{\n\t\t\t\t\t\t\t\t\t&Concurrently{},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tName: \"operator_class\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0], Attrs: []schema.Attr{&IndexOpClass{Name: \"int8_bloom_ops\"}}},\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0], Attrs: []schema.Attr{&IndexOpClass{Name: \"int8_minmax_ops\"}}},\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0], Attrs: []schema.Attr{&IndexOpClass{Name: \"int8_minmax_multi_ops\", Params: []struct{ N, V string }{{\"values_per_range\", \"8\"}}}}},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t\t&IndexType{T: IndexTypeBRIN},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tUnique: true,\n\t\t\t\t\t\t\t\t\tName:   \"nulls_distinct\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0]},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t\t&IndexNullsDistinct{V: true},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tUnique: true,\n\t\t\t\t\t\t\t\t\tName:   \"nulls_not_distinct\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0]},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t\t&IndexNullsDistinct{V: false},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tUnique: true,\n\t\t\t\t\t\t\t\t\tName:   \"unique_const_nulls_not_distinct\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0]},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t\t&IndexNullsDistinct{V: false},\n\t\t\t\t\t\t\t\t\t\t&Constraint{N: \"unique_const\", T: \"u\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP INDEX CONCURRENTLY \"drop_con\"`,\n\t\t\t\t\t\tReverse: `CREATE INDEX CONCURRENTLY \"drop_con\" ON \"users\" (\"id\")`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"users\" DROP CONSTRAINT \"id_nonzero\", ADD COLUMN \"name\" character varying(255) NOT NULL DEFAULT 'logged_in', ADD COLUMN \"last\" character varying(255) NOT NULL DEFAULT 'logged_in', ADD CONSTRAINT \"name_not_empty\" CHECK (\"name\" <> ''), ADD CONSTRAINT \"positive_id\" CHECK (\"id\" > 0) NOT VALID, DROP CONSTRAINT \"id_iseven\", ADD CONSTRAINT \"id_iseven\" CHECK ((\"id\") % 2 = 0), ADD CONSTRAINT \"unique_const\" UNIQUE NULLS NOT DISTINCT (\"id\")`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"users\" DROP CONSTRAINT \"unique_const_nulls_not_distinct\", DROP CONSTRAINT \"id_iseven\", ADD CONSTRAINT \"id_iseven\" CHECK (\"id\" % 2 = 0), DROP CONSTRAINT \"positive_id\", DROP CONSTRAINT \"name_not_empty\", DROP COLUMN \"last\", DROP COLUMN \"name\", ADD CONSTRAINT \"id_nonzero\" CHECK (\"id\" <> 0)`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE INDEX \"id_key\" ON \"users\" (\"id\" DESC) WHERE success`,\n\t\t\t\t\t\tReverse: `DROP INDEX \"id_key\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE INDEX \"id_brin\" ON \"users\" USING BRIN (\"id\" DESC) WITH (pages_per_range = 2)`,\n\t\t\t\t\t\tReverse: `DROP INDEX \"id_brin\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE INDEX \"include_key\" ON \"users\" (\"id\") INCLUDE (\"a\", \"b\")`,\n\t\t\t\t\t\tReverse: `DROP INDEX \"include_key\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE INDEX CONCURRENTLY \"add_con\" ON \"users\" (\"id\")`,\n\t\t\t\t\t\tReverse: `DROP INDEX CONCURRENTLY \"add_con\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE INDEX \"operator_class\" ON \"users\" USING BRIN (\"id\" int8_bloom_ops, \"id\", \"id\" int8_minmax_multi_ops(values_per_range=8))`,\n\t\t\t\t\t\tReverse: `DROP INDEX \"operator_class\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE UNIQUE INDEX \"nulls_distinct\" ON \"users\" (\"id\")`,\n\t\t\t\t\t\tReverse: `DROP INDEX \"nulls_distinct\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE UNIQUE INDEX \"nulls_not_distinct\" ON \"users\" (\"id\") NULLS NOT DISTINCT`,\n\t\t\t\t\t\tReverse: `DROP INDEX \"nulls_not_distinct\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `COMMENT ON COLUMN \"users\".\"name\" IS 'foo'`,\n\t\t\t\t\t\tReverse: `COMMENT ON COLUMN \"users\".\"name\" IS ''`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `COMMENT ON COLUMN \"users\".\"last\" IS 'bar'`,\n\t\t\t\t\t\tReverse: `COMMENT ON COLUMN \"users\".\"last\" IS ''`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `COMMENT ON INDEX \"id_key\" IS 'comment'`,\n\t\t\t\t\t\tReverse: `COMMENT ON INDEX \"id_key\" IS ''`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropColumn{\n\t\t\t\t\t\t\t\tC: &schema.Column{Name: \"name\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar\"}}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   &schema.Column{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&Identity{}, &schema.Comment{Text: \"comment\"}}},\n\t\t\t\t\t\t\t\tTo:     &schema.Column{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&Identity{Sequence: &Sequence{Start: 1024}}}},\n\t\t\t\t\t\t\t\tChange: schema.ChangeAttr | schema.ChangeComment,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"users\" DROP COLUMN \"name\", ALTER COLUMN \"id\" SET GENERATED BY DEFAULT SET START WITH 1024 SET INCREMENT BY 1 RESTART`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"users\" ALTER COLUMN \"id\" SET GENERATED BY DEFAULT SET START WITH 1 SET INCREMENT BY 1 RESTART, ADD COLUMN \"name\" character varying NOT NULL`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `COMMENT ON COLUMN \"users\".\"id\" IS ''`,\n\t\t\t\t\t\tReverse: `COMMENT ON COLUMN \"users\".\"id\" IS 'comment'`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropColumn{\n\t\t\t\t\t\t\t\tC: &schema.Column{Name: \"name\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar\"}}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   &schema.Column{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&Identity{Sequence: &Sequence{Start: 0, Last: 1025}}}},\n\t\t\t\t\t\t\t\tTo:     &schema.Column{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&Identity{Sequence: &Sequence{Start: 1024}}}},\n\t\t\t\t\t\t\t\tChange: schema.ChangeAttr,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"users\" DROP COLUMN \"name\", ALTER COLUMN \"id\" SET GENERATED BY DEFAULT SET START WITH 1024 SET INCREMENT BY 1`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"users\" ALTER COLUMN \"id\" SET GENERATED BY DEFAULT SET START WITH 1 SET INCREMENT BY 1, ADD COLUMN \"name\" character varying NOT NULL`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.AddAttr{\n\t\t\t\t\t\t\tA: &schema.Comment{Text: \"foo\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `COMMENT ON TABLE \"public\".\"users\" IS 'foo'`, Reverse: `COMMENT ON TABLE \"public\".\"users\" IS ''`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\t\t\tTo:   &schema.Comment{Text: \"foo\"},\n\t\t\t\t\t\t\tFrom: &schema.Comment{Text: \"bar\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `COMMENT ON TABLE \"public\".\"users\" IS 'foo'`, Reverse: `COMMENT ON TABLE \"public\".\"users\" IS 'bar'`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddObject{\n\t\t\t\t\tO: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t&schema.AddObject{\n\t\t\t\t\tO: &schema.EnumType{\n\t\t\t\t\t\tT:      \"status\",\n\t\t\t\t\t\tValues: []string{\"a\", \"b\"},\n\t\t\t\t\t\tSchema: schema.New(\"test\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewEnumColumn(\"state\", schema.EnumName(\"state\"), schema.EnumValues(\"on\", \"off\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t\t\tschema.NewEnumColumn(\"status\", schema.EnumName(\"status\"), schema.EnumValues(\"a\", \"b\"), schema.EnumSchema(schema.New(\"test\"))),\n\t\t\t\t\t\t)\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   &schema.Column{Name: \"state\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}}},\n\t\t\t\t\t\t\t\tTo:     users.Columns[0],\n\t\t\t\t\t\t\t\tChange: schema.ChangeType,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   &schema.Column{Name: \"status\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}}},\n\t\t\t\t\t\t\t\tTo:     users.Columns[1],\n\t\t\t\t\t\t\t\tChange: schema.ChangeType,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.DropColumn{\n\t\t\t\t\t\t\t\tC: schema.NewEnumColumn(\"dc1\", schema.EnumName(\"de\"), schema.EnumValues(\"on\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.DropColumn{\n\t\t\t\t\t\t\t\tC: schema.NewEnumColumn(\"dc2\", schema.EnumName(\"de\"), schema.EnumValues(\"on\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `CREATE TYPE \"public\".\"state\" AS ENUM ('on', 'off')`, Reverse: `DROP TYPE \"public\".\"state\"`},\n\t\t\t\t\t{Cmd: `CREATE TYPE \"test\".\"status\" AS ENUM ('a', 'b')`, Reverse: `DROP TYPE \"test\".\"status\"`},\n\t\t\t\t\t{Cmd: `ALTER TABLE \"public\".\"users\" ALTER COLUMN \"state\" TYPE \"public\".\"state\", ALTER COLUMN \"status\" TYPE \"test\".\"status\", DROP COLUMN \"dc1\", DROP COLUMN \"dc2\"`, Reverse: `ALTER TABLE \"public\".\"users\" ADD COLUMN \"dc2\" \"public\".\"de\" NOT NULL, ADD COLUMN \"dc1\" \"public\".\"de\" NOT NULL, ALTER COLUMN \"status\" TYPE text, ALTER COLUMN \"state\" TYPE text`},\n\t\t\t\t\t{Cmd: `DROP TYPE \"public\".\"de\"`, Reverse: `CREATE TYPE \"public\".\"de\" AS ENUM ('on')`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewEnumColumn(\"state\", schema.EnumName(\"state\"), schema.EnumValues(\"on\", \"off\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t\t\tschema.NewEnumColumn(\"status\", schema.EnumName(\"status\"), schema.EnumValues(\"on\", \"off\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t\t&schema.DropObject{\n\t\t\t\t\tO: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t&schema.DropObject{\n\t\t\t\t\tO: &schema.EnumType{\n\t\t\t\t\t\tT:      \"status\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `DROP TABLE \"public\".\"users\"`, Reverse: `CREATE TABLE \"public\".\"users\" (\"state\" \"public\".\"state\" NOT NULL, \"status\" \"public\".\"status\" NOT NULL)`},\n\t\t\t\t\t{Cmd: `DROP TYPE \"public\".\"state\"`, Reverse: `CREATE TYPE \"public\".\"state\" AS ENUM ('on', 'off')`},\n\t\t\t\t\t{Cmd: `DROP TYPE \"public\".\"status\"`, Reverse: `CREATE TYPE \"public\".\"status\" AS ENUM ('on', 'off')`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewEnumColumn(\"state\", schema.EnumName(\"state\"), schema.EnumValues(\"on\", \"off\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t\t\tschema.NewEnumColumn(\"status\", schema.EnumName(\"status\"), schema.EnumValues(\"on\", \"off\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `DROP TABLE \"public\".\"users\"`, Reverse: `CREATE TABLE \"public\".\"users\" (\"state\" \"public\".\"state\" NOT NULL, \"status\" \"public\".\"status\" NOT NULL)`},\n\t\t\t\t\t{Cmd: `DROP TYPE \"public\".\"state\"`, Reverse: `CREATE TYPE \"public\".\"state\" AS ENUM ('on', 'off')`},\n\t\t\t\t\t{Cmd: `DROP TYPE \"public\".\"status\"`, Reverse: `CREATE TYPE \"public\".\"status\" AS ENUM ('on', 'off')`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: func() []schema.Change {\n\t\t\t\ts := schema.New(\"public\").\n\t\t\t\t\tAddTables(\n\t\t\t\t\t\tschema.NewTable(\"t1\").\n\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\tschema.NewEnumColumn(\"state\", schema.EnumName(\"state\"), schema.EnumValues(\"on\", \"off\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\tschema.NewTable(\"t2\").\n\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\tschema.NewEnumColumn(\"state\", schema.EnumName(\"state\"), schema.EnumValues(\"on\", \"off\"), schema.EnumSchema(schema.New(\"public\"))),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\treturn []schema.Change{\n\t\t\t\t\t&schema.DropTable{\n\t\t\t\t\t\tT: s.Tables[0],\n\t\t\t\t\t},\n\t\t\t\t\t&schema.DropTable{\n\t\t\t\t\t\tT: s.Tables[1],\n\t\t\t\t\t},\n\t\t\t\t\t&schema.DropObject{\n\t\t\t\t\t\tO: &schema.EnumType{\n\t\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\t\tValues: []string{\"on\", \"off\"},\n\t\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t}(),\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP TABLE \"public\".\"t1\"`,\n\t\t\t\t\t\tReverse: `CREATE TABLE \"public\".\"t1\" (\"state\" \"public\".\"state\" NOT NULL)`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP TABLE \"public\".\"t2\"`,\n\t\t\t\t\t\tReverse: `CREATE TABLE \"public\".\"t2\" (\"state\" \"public\".\"state\" NOT NULL)`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP TYPE \"public\".\"state\"`,\n\t\t\t\t\t\tReverse: `CREATE TYPE \"public\".\"state\" AS ENUM ('on', 'off')`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Append enum value at the end.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyObject{\n\t\t\t\t\tFrom: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t\tTo: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\", \"unknown\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    false,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `ALTER TYPE \"public\".\"state\" ADD VALUE 'unknown'`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Append enum values at the beginning.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyObject{\n\t\t\t\t\tFrom: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t\tTo: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"unknown\", \"null\", \"on\", \"off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    false,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `ALTER TYPE \"public\".\"state\" ADD VALUE 'unknown' BEFORE 'on'`},\n\t\t\t\t\t{Cmd: `ALTER TYPE \"public\".\"state\" ADD VALUE 'null' AFTER 'unknown'`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Append values at beginning, middle and end.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyObject{\n\t\t\t\t\tFrom: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\", \"on-off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t\tTo: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"start\", \"on\", \"null\", \"off\", \"unknown\", \"on-off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    false,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `ALTER TYPE \"public\".\"state\" ADD VALUE 'start' BEFORE 'on'`},\n\t\t\t\t\t{Cmd: `ALTER TYPE \"public\".\"state\" ADD VALUE 'null' AFTER 'on'`},\n\t\t\t\t\t{Cmd: `ALTER TYPE \"public\".\"state\" ADD VALUE 'unknown' AFTER 'off'`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Enum reordering.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyObject{\n\t\t\t\t\tFrom: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t\tTo: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"off\", \"on\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t// Enum value dropping.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyObject{\n\t\t\t\t\tFrom: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t\tTo: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t// Modify column type and drop comment.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyObject{\n\t\t\t\t\tFrom: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t\tTo: &schema.EnumType{\n\t\t\t\t\t\tT:      \"state\",\n\t\t\t\t\t\tValues: []string{\"on\", \"off\", \"unknown\"},\n\t\t\t\t\t\tSchema: schema.New(\"public\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewEnumColumn(\"state\", schema.EnumName(\"state\"), schema.EnumValues(\"on\", \"off\")),\n\t\t\t\t\t\t)\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   &schema.Column{Name: \"state\", Type: &schema.ColumnType{Type: &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\"}}}, Attrs: []schema.Attr{&schema.Comment{Text: \"foo\"}}},\n\t\t\t\t\t\t\t\tTo:     &schema.Column{Name: \"state\", Type: &schema.ColumnType{Type: &schema.EnumType{T: \"state\", Values: []string{\"on\", \"off\", \"unknown\"}}}},\n\t\t\t\t\t\t\t\tChange: schema.ChangeComment,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    false,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `ALTER TYPE \"public\".\"state\" ADD VALUE 'unknown'`},\n\t\t\t\t\t{Cmd: `COMMENT ON COLUMN \"public\".\"users\".\"state\" IS ''`, Reverse: `COMMENT ON COLUMN \"public\".\"users\".\"state\" IS 'foo'`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Modify column comment.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"state\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   &schema.Column{Name: \"state\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}}, Attrs: []schema.Attr{&schema.Comment{Text: \"bar\"}}},\n\t\t\t\t\t\t\t\tTo:     &schema.Column{Name: \"state\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}}, Attrs: []schema.Attr{&schema.Comment{Text: \"foo\"}}},\n\t\t\t\t\t\t\t\tChange: schema.ChangeComment,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `COMMENT ON COLUMN \"users\".\"state\" IS 'foo'`, Reverse: `COMMENT ON COLUMN \"users\".\"state\" IS 'bar'`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Modify index comment.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifyIndex{\n\t\t\t\t\t\t\t\tFrom: schema.NewIndex(\"id_key\").\n\t\t\t\t\t\t\t\t\tAddColumns(users.Columns[0]).\n\t\t\t\t\t\t\t\t\tSetComment(\"foo\"),\n\t\t\t\t\t\t\t\tTo: schema.NewIndex(\"id_key\").\n\t\t\t\t\t\t\t\t\tAddColumns(users.Columns[0]).\n\t\t\t\t\t\t\t\t\tSetComment(\"bar\"),\n\t\t\t\t\t\t\t\tChange: schema.ChangeComment,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: `COMMENT ON INDEX \"id_key\" IS 'bar'`, Reverse: `COMMENT ON INDEX \"id_key\" IS 'foo'`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Modify default values.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t{Name: \"one\", Default: &schema.Literal{V: \"'one'\"}, Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t{Name: \"two\", Default: &schema.Literal{V: \"'two'\"}, Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   &schema.Column{Name: \"one\", Default: &schema.Literal{V: \"'one'\"}, Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t\tTo:     &schema.Column{Name: \"one\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t\tChange: schema.ChangeDefault,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   &schema.Column{Name: \"two\", Default: &schema.Literal{V: \"'two'\"}, Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t\tTo:     &schema.Column{Name: \"two\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t\tChange: schema.ChangeDefault,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   &schema.Column{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&Identity{}}},\n\t\t\t\t\t\t\t\tTo:     &schema.Column{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}, Attrs: []schema.Attr{&Identity{Sequence: &Sequence{Start: 1024}}}},\n\t\t\t\t\t\t\t\tChange: schema.ChangeAttr,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"users\" ALTER COLUMN \"one\" DROP DEFAULT, ALTER COLUMN \"two\" DROP DEFAULT, ALTER COLUMN \"id\" SET GENERATED BY DEFAULT SET START WITH 1024 SET INCREMENT BY 1 RESTART`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"users\" ALTER COLUMN \"id\" SET GENERATED BY DEFAULT SET START WITH 1 SET INCREMENT BY 1 RESTART, ALTER COLUMN \"two\" SET DEFAULT 'two', ALTER COLUMN \"one\" SET DEFAULT 'one'`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.RenameTable{\n\t\t\t\t\tFrom: schema.NewTable(\"t1\").SetSchema(schema.New(\"s1\")),\n\t\t\t\t\tTo:   schema.NewTable(\"t2\").SetSchema(schema.New(\"s2\")),\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"s1\".\"t1\" RENAME TO \"s2\".\"t2\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"s2\".\"t2\" RENAME TO \"s1\".\"t1\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"t1\").SetSchema(schema.New(\"s1\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameColumn{\n\t\t\t\t\t\t\tFrom: schema.NewColumn(\"a\"),\n\t\t\t\t\t\t\tTo:   schema.NewColumn(\"b\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"s1\".\"t1\" RENAME COLUMN \"a\" TO \"b\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"s1\".\"t1\" RENAME COLUMN \"b\" TO \"a\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"t1\").SetSchema(schema.New(\"s1\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameColumn{\n\t\t\t\t\t\t\tFrom: schema.NewColumn(\"a\"),\n\t\t\t\t\t\t\tTo:   schema.NewColumn(\"b\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\tC: schema.NewIntColumn(\"c\", \"int\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"s1\".\"t1\" ADD COLUMN \"c\" integer NOT NULL`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"s1\".\"t1\" DROP COLUMN \"c\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"s1\".\"t1\" RENAME COLUMN \"a\" TO \"b\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"s1\".\"t1\" RENAME COLUMN \"b\" TO \"a\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"t1\").SetSchema(schema.New(\"s1\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameIndex{\n\t\t\t\t\t\t\tFrom: schema.NewIndex(\"a\"),\n\t\t\t\t\t\t\tTo:   schema.NewIndex(\"b\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) { o.SchemaQualifier = new(string) },\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER INDEX \"a\" RENAME TO \"b\"`,\n\t\t\t\t\t\tReverse: `ALTER INDEX \"b\" RENAME TO \"a\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"t1\").SetSchema(schema.New(\"s1\")),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameIndex{\n\t\t\t\t\t\t\tFrom: schema.NewIndex(\"a\"),\n\t\t\t\t\t\t\tTo:   schema.NewIndex(\"b\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER INDEX \"s1\".\"a\" RENAME TO \"b\"`,\n\t\t\t\t\t\tReverse: `ALTER INDEX \"s1\".\"b\" RENAME TO \"a\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Invalid serial type.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &SerialType{T: \"serial\"}, Null: true}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t// Drop serial sequence.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"c1\", \"integer\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"c2\", \"integer\"),\n\t\t\t\t\t\t),\n\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tFrom:   schema.NewColumn(\"c1\").SetType(&SerialType{T: \"smallserial\"}),\n\t\t\t\t\t\t\tTo:     schema.NewIntColumn(\"c1\", \"integer\"),\n\t\t\t\t\t\t\tChange: schema.ChangeType,\n\t\t\t\t\t\t\tExtra: []schema.Clause{\n\t\t\t\t\t\t\t\t&ConvertUsing{X: \"c1::int\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tFrom:   schema.NewColumn(\"c2\").SetType(&SerialType{T: \"serial\", SequenceName: \"previous_name\"}),\n\t\t\t\t\t\t\tTo:     schema.NewIntColumn(\"c2\", \"integer\"),\n\t\t\t\t\t\t\tChange: schema.ChangeType,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"public\".\"posts\" ALTER COLUMN \"c1\" DROP DEFAULT, ALTER COLUMN \"c1\" TYPE integer USING c1::int, ALTER COLUMN \"c2\" DROP DEFAULT`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"public\".\"posts\" ALTER COLUMN \"c2\" SET DEFAULT nextval('\"public\".\"previous_name\"'), ALTER COLUMN \"c1\" SET DEFAULT nextval('\"public\".\"posts_c1_seq\"'), ALTER COLUMN \"c1\" TYPE smallint`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP SEQUENCE IF EXISTS \"public\".\"posts_c1_seq\"`,\n\t\t\t\t\t\tReverse: `CREATE SEQUENCE IF NOT EXISTS \"public\".\"posts_c1_seq\" OWNED BY \"public\".\"posts\".\"c1\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP SEQUENCE IF EXISTS \"public\".\"previous_name\"`,\n\t\t\t\t\t\tReverse: `CREATE SEQUENCE IF NOT EXISTS \"public\".\"previous_name\" OWNED BY \"public\".\"posts\".\"c2\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Add serial sequence.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewColumn(\"c1\").SetType(&SerialType{T: \"serial\"}),\n\t\t\t\t\t\t\tschema.NewColumn(\"c2\").SetType(&SerialType{T: \"bigserial\"}),\n\t\t\t\t\t\t),\n\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tFrom:   schema.NewIntColumn(\"c1\", \"integer\"),\n\t\t\t\t\t\t\tTo:     schema.NewColumn(\"c1\").SetType(&SerialType{T: \"serial\"}),\n\t\t\t\t\t\t\tChange: schema.ChangeType,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tFrom:   schema.NewIntColumn(\"c2\", \"integer\"),\n\t\t\t\t\t\t\tTo:     schema.NewColumn(\"c2\").SetType(&SerialType{T: \"bigserial\"}),\n\t\t\t\t\t\t\tChange: schema.ChangeType,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE SEQUENCE IF NOT EXISTS \"public\".\"posts_c1_seq\" OWNED BY \"public\".\"posts\".\"c1\"`,\n\t\t\t\t\t\tReverse: `DROP SEQUENCE IF EXISTS \"public\".\"posts_c1_seq\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE SEQUENCE IF NOT EXISTS \"public\".\"posts_c2_seq\" OWNED BY \"public\".\"posts\".\"c2\"`,\n\t\t\t\t\t\tReverse: `DROP SEQUENCE IF EXISTS \"public\".\"posts_c2_seq\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"public\".\"posts\" ALTER COLUMN \"c1\" SET DEFAULT nextval('\"public\".\"posts_c1_seq\"'), ALTER COLUMN \"c2\" SET DEFAULT nextval('\"public\".\"posts_c2_seq\"'), ALTER COLUMN \"c2\" TYPE bigint`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"public\".\"posts\" ALTER COLUMN \"c2\" DROP DEFAULT, ALTER COLUMN \"c2\" TYPE integer, ALTER COLUMN \"c1\" DROP DEFAULT`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Change underlying sequence type.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewColumn(\"c1\").SetType(&SerialType{T: \"serial\"}),\n\t\t\t\t\t\t\tschema.NewColumn(\"c2\").SetType(&SerialType{T: \"bigserial\"}),\n\t\t\t\t\t\t),\n\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tFrom:   schema.NewColumn(\"c1\").SetType(&SerialType{T: \"smallserial\"}),\n\t\t\t\t\t\t\tTo:     schema.NewColumn(\"c1\").SetType(&SerialType{T: \"serial\"}),\n\t\t\t\t\t\t\tChange: schema.ChangeType,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tFrom:   schema.NewColumn(\"c2\").SetType(&SerialType{T: \"serial\"}),\n\t\t\t\t\t\t\tTo:     schema.NewColumn(\"c2\").SetType(&SerialType{T: \"bigserial\"}),\n\t\t\t\t\t\t\tChange: schema.ChangeType,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"public\".\"posts\" ALTER COLUMN \"c1\" TYPE integer, ALTER COLUMN \"c2\" TYPE bigint`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"public\".\"posts\" ALTER COLUMN \"c2\" TYPE integer, ALTER COLUMN \"c1\" TYPE smallint`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Empty qualifier.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddObject{\n\t\t\t\t\tO: &schema.EnumType{\n\t\t\t\t\t\tT:      \"enum\",\n\t\t\t\t\t\tValues: []string{\"a\"},\n\t\t\t\t\t\tSchema: schema.New(\"ignored\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\tSetSchema(schema.New(\"test1\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewEnumColumn(\"c1\", schema.EnumName(\"enum\"), schema.EnumValues(\"a\"), schema.EnumSchema(schema.New(\"test2\"))),\n\t\t\t\t\t\t),\n\t\t\t\t},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) { o.SchemaQualifier = new(string) },\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE TYPE \"enum\" AS ENUM ('a')`,\n\t\t\t\t\t\tReverse: `DROP TYPE \"enum\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE TABLE \"posts\" (\"c1\" \"enum\" NOT NULL)`,\n\t\t\t\t\t\tReverse: `DROP TABLE \"posts\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Empty sequence qualifier.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewColumn(\"c1\").SetType(&SerialType{T: \"serial\"}),\n\t\t\t\t\t\t),\n\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tFrom:   schema.NewIntColumn(\"c1\", \"integer\"),\n\t\t\t\t\t\t\tTo:     schema.NewColumn(\"c1\").SetType(&SerialType{T: \"serial\"}),\n\t\t\t\t\t\t\tChange: schema.ChangeType,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) { o.SchemaQualifier = new(string) },\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE SEQUENCE IF NOT EXISTS \"posts_c1_seq\" OWNED BY \"posts\".\"c1\"`,\n\t\t\t\t\t\tReverse: `DROP SEQUENCE IF EXISTS \"posts_c1_seq\"`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"posts\" ALTER COLUMN \"c1\" SET DEFAULT nextval('\"posts_c1_seq\"')`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"posts\" ALTER COLUMN \"c1\" DROP DEFAULT`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Empty index qualifier.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\tSetSchema(schema.New(\"public\")).\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"c\", \"int\"),\n\t\t\t\t\t\t),\n\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\tI: schema.NewIndex(\"i\").AddColumns(schema.NewIntColumn(\"c\", \"int\")),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) { o.SchemaQualifier = new(string) },\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `CREATE INDEX \"i\" ON \"posts\" (\"c\")`,\n\t\t\t\t\t\tReverse: `DROP INDEX \"i\"`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Foreign keys should be dropped before the tables they reference.\n\t\t{\n\t\t\tchanges: func() []schema.Change {\n\t\t\t\tusersT := schema.NewTable(\"users\").SetSchema(schema.New(\"public\")).AddColumns(schema.NewIntColumn(\"id\", \"int\"))\n\t\t\t\tpostsT := schema.NewTable(\"posts\").SetSchema(schema.New(\"public\")).\n\t\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\"), schema.NewIntColumn(\"author_id\", \"int\"))\n\t\t\t\tpostsT.AddForeignKeys(schema.NewForeignKey(\"author\").AddColumns(postsT.Columns[1]).SetRefTable(usersT).AddRefColumns(usersT.Columns...))\n\t\t\t\treturn []schema.Change{\n\t\t\t\t\t&schema.DropTable{T: usersT},\n\t\t\t\t\t&schema.ModifyTable{T: postsT, Changes: []schema.Change{&schema.DropForeignKey{F: postsT.ForeignKeys[0]}}},\n\t\t\t\t}\n\t\t\t}(),\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) { o.SchemaQualifier = new(string) },\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"posts\" DROP CONSTRAINT \"author\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"posts\" ADD CONSTRAINT \"author\" FOREIGN KEY (\"author_id\") REFERENCES \"users\" (\"id\")`,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `DROP TABLE \"users\"`,\n\t\t\t\t\t\tReverse: `CREATE TABLE \"users\" (\"id\" integer NOT NULL)`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Empty qualifier in multi-schema mode should fail.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{T: schema.NewTable(\"t1\").SetSchema(schema.New(\"s1\")).AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t\t\t\t&schema.AddTable{T: schema.NewTable(\"t2\").SetSchema(schema.New(\"s2\")).AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) { o.SchemaQualifier = new(string) },\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewColumn(\"name\").SetType(&schema.StringType{T: \"text\"}).AddAttrs(&schema.Collation{V: \"ja-x-icu\"})),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\tFrom:   schema.NewColumn(\"name\").SetType(&schema.StringType{T: \"text\"}),\n\t\t\t\t\t\t\tTo:     schema.NewColumn(\"name\").SetType(&schema.StringType{T: \"text\"}).AddAttrs(&schema.Collation{V: \"ja-x-icu\"}),\n\t\t\t\t\t\t\tChange: schema.ChangeType,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\twantPlan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     `ALTER TABLE \"users\" ALTER COLUMN \"name\" TYPE text COLLATE \"ja-x-icu\"`,\n\t\t\t\t\t\tReverse: `ALTER TABLE \"users\" ALTER COLUMN \"name\" TYPE text`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Adding view is not supported in OSS.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddView{\n\t\t\t\t\tV: schema.NewView(\"v1\", \"SELECT * FROM users\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tdb, mk, err := sqlmock.New()\n\t\t\trequire.NoError(t, err)\n\t\t\tm := mock{mk}\n\t\t\tm.version(\"130000\")\n\t\t\tif tt.mock != nil {\n\t\t\t\ttt.mock(m)\n\t\t\t}\n\t\t\tdrv, err := Open(db)\n\t\t\trequire.NoError(t, err)\n\t\t\tplan, err := drv.PlanChanges(context.Background(), \"wantPlan\", tt.changes, tt.options...)\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err, \"expect plan to fail\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.wantPlan.Reversible, plan.Reversible)\n\t\t\trequire.Equal(t, tt.wantPlan.Transactional, plan.Transactional)\n\t\t\tfor i, c := range plan.Changes {\n\t\t\t\trequire.Equal(t, tt.wantPlan.Changes[i].Cmd, c.Cmd)\n\t\t\t\trequire.Equal(t, tt.wantPlan.Changes[i].Reverse, c.Reverse)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestDefaultPlan(t *testing.T) {\n\tchanges, err := DefaultPlan.PlanChanges(context.Background(), \"plan\", []schema.Change{\n\t\t&schema.AddTable{T: schema.NewTable(\"t1\").SetSchema(schema.New(\"s1\")).AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, 1, len(changes.Changes))\n\trequire.Equal(t, `CREATE TABLE \"s1\".\"t1\" (\"a\" integer NOT NULL)`, changes.Changes[0].Cmd)\n\n\terr = DefaultPlan.ApplyChanges(context.Background(), []schema.Change{\n\t\t&schema.AddTable{T: schema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t})\n\trequire.EqualError(t, err, `create \"t1\" table: cannot execute statements without a database connection. use Open to create a new Driver`)\n}\n\nfunc TestIndentedPlan(t *testing.T) {\n\ttests := []struct {\n\t\tT   *schema.Table\n\t\tCmd string\n\t}{\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\tCmd: `CREATE TABLE \"t1\" (\n  \"a\" integer NOT NULL\n)`,\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t),\n\t\t\tCmd: `CREATE TABLE \"t1\" (\n  \"a\" integer NOT NULL,\n  \"b\" integer NOT NULL\n)`,\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tSetPrimaryKey(\n\t\t\t\t\tschema.NewPrimaryKey(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\t),\n\t\t\tCmd: `CREATE TABLE \"t1\" (\n  \"a\" integer NOT NULL,\n  \"b\" integer NOT NULL,\n  \"id\" integer NOT NULL,\n  PRIMARY KEY (\"id\")\n)`,\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tAddForeignKeys(\n\t\t\t\t\tschema.NewForeignKey(\"fk1\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t\tschema.NewForeignKey(\"fk2\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t),\n\t\t\tCmd: `CREATE TABLE \"t1\" (\n  \"a\" integer NOT NULL,\n  \"b\" integer NOT NULL,\n  CONSTRAINT \"fk1\" FOREIGN KEY (\"a\") REFERENCES \"t2\" (\"a\"),\n  CONSTRAINT \"fk2\" FOREIGN KEY (\"a\") REFERENCES \"t2\" (\"a\")\n)`,\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tSetPrimaryKey(\n\t\t\t\t\tschema.NewPrimaryKey(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\t).\n\t\t\t\tAddForeignKeys(\n\t\t\t\t\tschema.NewForeignKey(\"fk1\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t\tschema.NewForeignKey(\"fk2\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t).\n\t\t\t\tAddChecks(\n\t\t\t\t\tschema.NewCheck().SetName(\"ck1\").SetExpr(\"a > 0\"),\n\t\t\t\t\tschema.NewCheck().SetName(\"ck2\").SetExpr(\"a > 0\"),\n\t\t\t\t),\n\t\t\tCmd: `CREATE TABLE \"t1\" (\n  \"a\" integer NOT NULL,\n  \"b\" integer NOT NULL,\n  \"id\" integer NOT NULL,\n  PRIMARY KEY (\"id\"),\n  CONSTRAINT \"fk1\" FOREIGN KEY (\"a\") REFERENCES \"t2\" (\"a\"),\n  CONSTRAINT \"fk2\" FOREIGN KEY (\"a\") REFERENCES \"t2\" (\"a\"),\n  CONSTRAINT \"ck1\" CHECK (a > 0),\n  CONSTRAINT \"ck2\" CHECK (a > 0)\n)`,\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tdb, mk, err := sqlmock.New()\n\t\t\trequire.NoError(t, err)\n\t\t\tmock{mk}.version(\"130000\")\n\t\t\tdrv, err := Open(db)\n\t\t\trequire.NoError(t, err)\n\t\t\tplan, err := drv.PlanChanges(context.Background(), \"wantPlan\", []schema.Change{&schema.AddTable{T: tt.T}}, func(opts *migrate.PlanOptions) {\n\t\t\t\topts.Indent = \"  \"\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, plan.Changes, 1)\n\t\t\trequire.Equal(t, tt.Cmd, plan.Changes[0].Cmd)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "sql/postgres/postgrescheck/postgrescheck.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage postgrescheck\n\nimport (\n\t\"fmt\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/postgres\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlcheck/condrop\"\n\t\"ariga.io/atlas/sql/sqlcheck/datadepend\"\n\t\"ariga.io/atlas/sql/sqlcheck/destructive\"\n\t\"ariga.io/atlas/sql/sqlcheck/incompatible\"\n)\n\nfunc addNotNull(p *datadepend.ColumnPass) (diags []sqlcheck.Diagnostic, err error) {\n\ttt, err := postgres.FormatType(p.Column.Type.Type)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []sqlcheck.Diagnostic{\n\t\t{\n\t\t\tPos: p.Change.Stmt.Pos,\n\t\t\tText: fmt.Sprintf(\n\t\t\t\t\"Adding a non-nullable %q column %q will fail in case table %q is not empty\",\n\t\t\t\ttt, p.Column.Name, p.Table.Name,\n\t\t\t),\n\t\t},\n\t}, nil\n}\n\nfunc analyzers(r *schemahcl.Resource) ([]sqlcheck.Analyzer, error) {\n\tds, err := destructive.New(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcd, err := condrop.New(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdd, err := datadepend.New(r, datadepend.Handler{\n\t\tAddNotNull: addNotNull,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbc, err := incompatible.New(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []sqlcheck.Analyzer{ds, dd, cd, bc}, nil\n}\n"
  },
  {
    "path": "sql/postgres/postgrescheck/postgrescheck_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgrescheck\n\nimport (\n\t\"ariga.io/atlas/sql/postgres\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n)\n\nfunc init() {\n\tsqlcheck.Register(postgres.DriverName, analyzers)\n}\n"
  },
  {
    "path": "sql/postgres/postgrescheck/postgrescheck_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage postgrescheck_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/postgres\"\n\t_ \"ariga.io/atlas/sql/postgres/postgrescheck\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDataDepend_MightFail(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE users\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"a\", postgres.TypeInt),\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"b\", postgres.TypeInt),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewTimeColumn(\"b\", postgres.TypeInt)},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\tazs, err := sqlcheck.AnalyzerFor(postgres.DriverName, nil)\n\trequire.NoError(t, err)\n\trequire.NoError(t, sqlcheck.Analyzers(azs).Analyze(context.Background(), pass))\n\trequire.Equal(t, report.Diagnostics[0].Text, `Adding a non-nullable \"int\" column \"b\" will fail in case table \"users\" is not empty`)\n}\n\ntype testFile struct {\n\tname string\n\tmigrate.File\n}\n\nfunc (t testFile) Name() string {\n\treturn t.name\n}\n"
  },
  {
    "path": "sql/postgres/sqlspec_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/specutil\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/postgres/internal/postgresop\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlspec\"\n\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\ntype (\n\tdoc struct {\n\t\tTables        []*sqlspec.Table    `spec:\"table\"`\n\t\tViews         []*sqlspec.View     `spec:\"view\"`\n\t\tMaterialized  []*sqlspec.View     `spec:\"materialized\"`\n\t\tEnums         []*enum             `spec:\"enum\"`\n\t\tDomains       []*domain           `spec:\"domain\"`\n\t\tComposites    []*composite        `spec:\"composite\"`\n\t\tSequences     []*sqlspec.Sequence `spec:\"sequence\"`\n\t\tFuncs         []*sqlspec.Func     `spec:\"function\"`\n\t\tProcs         []*sqlspec.Func     `spec:\"procedure\"`\n\t\tAggregates    []*aggregate        `spec:\"aggregate\"`\n\t\tTriggers      []*sqlspec.Trigger  `spec:\"trigger\"`\n\t\tPolicies      []*policy           `spec:\"policy\"`\n\t\tEventTriggers []*eventTrigger     `spec:\"event_trigger\"`\n\t\tExtensions    []*extension        `spec:\"extension\"`\n\t\tSchemas       []*sqlspec.Schema   `spec:\"schema\"`\n\t}\n\n\t// Enum holds a specification for an enum type.\n\tenum struct {\n\t\tName      string         `spec:\",name\"`\n\t\tQualifier string         `spec:\",qualifier\"`\n\t\tSchema    *schemahcl.Ref `spec:\"schema\"`\n\t\tValues    []string       `spec:\"values\"`\n\t\tschemahcl.DefaultExtension\n\t}\n\n\t// domain holds a specification for a domain type.\n\tdomain struct {\n\t\tName      string           `spec:\",name\"`\n\t\tQualifier string           `spec:\",qualifier\"`\n\t\tSchema    *schemahcl.Ref   `spec:\"schema\"`\n\t\tType      *schemahcl.Type  `spec:\"type\"`\n\t\tNull      bool             `spec:\"null\"`\n\t\tDefault   cty.Value        `spec:\"default\"`\n\t\tChecks    []*sqlspec.Check `spec:\"check\"`\n\t\tschemahcl.DefaultExtension\n\t}\n\n\t// composite holds a specification for a composite type.\n\tcomposite struct {\n\t\tName      string            `spec:\",name\"`\n\t\tQualifier string            `spec:\",qualifier\"`\n\t\tSchema    *schemahcl.Ref    `spec:\"schema\"`\n\t\tFields    []*compositeField `spec:\"field\"`\n\t\tschemahcl.DefaultExtension\n\t}\n\n\t// compositeField holds a specification for a field in a composite type.\n\t// The extension might hold optional attributes such as collation.\n\tcompositeField struct {\n\t\tName string          `spec:\",name\"`\n\t\tType *schemahcl.Type `spec:\"type\"`\n\t\tschemahcl.DefaultExtension\n\t}\n\n\t// extension holds a specification for a postgres extension.\n\t// Note, extension names are unique within a realm (database).\n\textension struct {\n\t\tName string `spec:\",name\"`\n\t\t// Schema, version and comment are conditionally\n\t\t// added to the extension definition.\n\t\tschemahcl.DefaultExtension\n\t}\n\n\t// eventTrigger holds a specification for a postgres event trigger.\n\t// Note, event trigger names are unique within a realm (database).\n\teventTrigger struct {\n\t\tName string `spec:\",name\"`\n\t\t// Schema, version and comment are conditionally\n\t\t// added to the extension definition.\n\t\tschemahcl.DefaultExtension\n\t}\n\n\t// aggregate holds the specification for an aggregation function.\n\taggregate struct {\n\t\tName      string             `spec:\",name\"`\n\t\tQualifier string             `spec:\",qualifier\"`\n\t\tSchema    *schemahcl.Ref     `spec:\"schema\"`\n\t\tArgs      []*sqlspec.FuncArg `spec:\"arg\"`\n\t\t// state_type, state_func and rest of the attributes\n\t\t// are appended after the function arguments.\n\t\tschemahcl.DefaultExtension\n\t}\n\n\t// Policy defines row-level security policy for a table.\n\t// See: https://www.postgresql.org/docs/current/view-pg-policies.html.\n\tpolicy struct {\n\t\tName string         `spec:\",name\"`\n\t\tOn   *schemahcl.Ref `spec:\"on\"`\n\t\t// Rest of the attributes are appended after the table reference.\n\t\tschemahcl.DefaultExtension\n\t}\n)\n\n// merge merges the doc d1 into d.\nfunc (d *doc) merge(d1 *doc) {\n\td.Enums = append(d.Enums, d1.Enums...)\n\td.Funcs = append(d.Funcs, d1.Funcs...)\n\td.Procs = append(d.Procs, d1.Procs...)\n\td.Views = append(d.Views, d1.Views...)\n\td.Tables = append(d.Tables, d1.Tables...)\n\td.Domains = append(d.Domains, d1.Domains...)\n\td.Composites = append(d.Composites, d1.Composites...)\n\td.Schemas = append(d.Schemas, d1.Schemas...)\n\td.Aggregates = append(d.Aggregates, d1.Aggregates...)\n\td.Sequences = append(d.Sequences, d1.Sequences...)\n\td.Extensions = append(d.Extensions, d1.Extensions...)\n\td.Triggers = append(d.Triggers, d1.Triggers...)\n\td.Policies = append(d.Policies, d1.Policies...)\n\td.EventTriggers = append(d.EventTriggers, d1.EventTriggers...)\n\td.Materialized = append(d.Materialized, d1.Materialized...)\n}\n\nfunc (d *doc) ScanDoc() *specutil.ScanDoc {\n\treturn &specutil.ScanDoc{\n\t\tSchemas:      d.Schemas,\n\t\tTables:       d.Tables,\n\t\tViews:        d.Views,\n\t\tFuncs:        d.Funcs,\n\t\tProcs:        d.Procs,\n\t\tTriggers:     d.Triggers,\n\t\tMaterialized: d.Materialized,\n\t}\n}\n\n// Label returns the defaults label used for the enum resource.\nfunc (e *enum) Label() string { return e.Name }\n\n// QualifierLabel returns the qualifier label used for the enum resource, if any.\nfunc (e *enum) QualifierLabel() string { return e.Qualifier }\n\n// SetQualifier sets the qualifier label used for the enum resource.\nfunc (e *enum) SetQualifier(q string) { e.Qualifier = q }\n\n// SchemaRef returns the schema reference for the enum.\nfunc (e *enum) SchemaRef() *schemahcl.Ref { return e.Schema }\n\n// Label returns the defaults label used for the domain resource.\nfunc (d *domain) Label() string { return d.Name }\n\n// QualifierLabel returns the qualifier label used for the domain resource, if any.\nfunc (d *domain) QualifierLabel() string { return d.Qualifier }\n\n// SetQualifier sets the qualifier label used for the domain resource.\nfunc (d *domain) SetQualifier(q string) { d.Qualifier = q }\n\n// SchemaRef returns the schema reference for the domain.\nfunc (d *domain) SchemaRef() *schemahcl.Ref { return d.Schema }\n\n// Label returns the defaults label used for the composite resource.\nfunc (c *composite) Label() string { return c.Name }\n\n// QualifierLabel returns the qualifier label used for the composite resource, if any.\nfunc (c *composite) QualifierLabel() string { return c.Qualifier }\n\n// SetQualifier sets the qualifier label used for the composite resource.\nfunc (c *composite) SetQualifier(q string) { c.Qualifier = q }\n\n// SchemaRef returns the schema reference for the composite.\nfunc (c *composite) SchemaRef() *schemahcl.Ref { return c.Schema }\n\n// Label returns the defaults label used for the aggregate resource.\nfunc (a *aggregate) Label() string { return a.Name }\n\n// QualifierLabel returns the qualifier label used for the aggregate resource, if any.\nfunc (a *aggregate) QualifierLabel() string { return a.Qualifier }\n\n// SetQualifier sets the qualifier label used for the aggregate resource.\nfunc (a *aggregate) SetQualifier(q string) { a.Qualifier = q }\n\n// SchemaRef returns the schema reference for the aggregate.\nfunc (a *aggregate) SchemaRef() *schemahcl.Ref { return a.Schema }\n\nfunc init() {\n\tschemahcl.Register(\"enum\", &enum{})\n\tschemahcl.Register(\"domain\", &domain{})\n\tschemahcl.Register(\"policy\", &policy{})\n\tschemahcl.Register(\"composite\", &composite{})\n\tschemahcl.Register(\"aggregate\", &aggregate{})\n\tschemahcl.Register(\"extension\", &extension{})\n\tschemahcl.Register(\"event_trigger\", &eventTrigger{})\n}\n\n// Codec for schemahcl.\ntype Codec struct {\n\tState *schemahcl.State\n}\n\n// Eval evaluates an Atlas DDL document into v using the input.\nfunc (c *Codec) Eval(p *hclparse.Parser, v any, input map[string]cty.Value) error {\n\treturn c.EvalOptions(p, v, &schemahcl.EvalOptions{Variables: input})\n}\n\n// EvalOptions decodes the HCL with the given options.\nfunc (c *Codec) EvalOptions(p *hclparse.Parser, v any, opts *schemahcl.EvalOptions) error {\n\tswitch v := v.(type) {\n\tcase *schema.Realm:\n\t\tvar d doc\n\t\tif err := c.State.EvalOptions(p, &d, opts); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := specutil.Scan(v, d.ScanDoc(), scanFuncs); err != nil {\n\t\t\treturn fmt.Errorf(\"specutil: failed converting to *schema.Realm: %w\", err)\n\t\t}\n\t\tif err := convertTypes(&d, v); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := convertAggregate(&d, v); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := convertSequences(d.Tables, d.Sequences, v); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := convertPolicies(d.Tables, d.Policies, v); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := convertExtensions(d.Extensions, v); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := convertEventTriggers(d.EventTriggers, v); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := normalizeRealm(v); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase *schema.Schema:\n\t\tvar d doc\n\t\tif err := c.State.EvalOptions(p, &d, opts); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(d.Schemas) != 1 {\n\t\t\treturn fmt.Errorf(\"specutil: expecting document to contain a single schema, got %d\", len(d.Schemas))\n\t\t}\n\t\tr := &schema.Realm{}\n\t\tif err := specutil.Scan(r, d.ScanDoc(), scanFuncs); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := convertTypes(&d, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := convertAggregate(&d, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := convertSequences(d.Tables, d.Sequences, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := convertPolicies(d.Tables, d.Policies, r); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Extensions are skipped in schema scope.\n\t\tif err := normalizeRealm(r); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t*v = *r.Schemas[0]\n\tcase schema.Schema, schema.Realm:\n\t\treturn fmt.Errorf(\"postgres: Eval expects a pointer: received %[1]T, expected *%[1]T\", v)\n\tdefault:\n\t\treturn fmt.Errorf(\"postgres: unexpected type %T\", v)\n\t}\n\treturn nil\n}\n\n// MarshalSpec marshals v into an Atlas DDL document using a schemahcl.Marshaler.\nfunc (c *Codec) MarshalSpec(v any) ([]byte, error) {\n\tvar (\n\t\td  doc\n\t\tts []*schema.Trigger\n\t)\n\tswitch rv := v.(type) {\n\tcase *schema.Schema:\n\t\td1, trs, err := schemaSpec(rv)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"specutil: failed converting schema to spec: %w\", err)\n\t\t}\n\t\tts = trs\n\t\td.merge(d1)\n\t\tif err := schemasObjectSpec(&d, rv); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase *schema.Realm:\n\t\tfor _, s := range rv.Schemas {\n\t\t\td1, trs, err := schemaSpec(s)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"specutil: failed converting schema to spec: %w\", err)\n\t\t\t}\n\t\t\td.merge(d1)\n\t\t\tts = append(ts, trs...)\n\t\t}\n\t\tif err := realmObjectsSpec(&d, rv); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyObjects(d.Tables); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyObjects(d.Views); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyObjects(d.Materialized); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyObjects(d.Aggregates); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyObjects(d.Enums); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyObjects(d.Domains); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyObjects(d.Composites); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyObjects(d.Sequences); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyObjects(d.Funcs); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyObjects(d.Procs); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err := specutil.QualifyReferences(d.Tables, rv); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"specutil: failed marshaling spec. %T is not supported\", v)\n\t}\n\tif err := triggersSpec(ts, &d); err != nil {\n\t\treturn nil, err\n\t}\n\treturn c.State.MarshalSpec(&d)\n}\n\nvar (\n\tcodec = &Codec{\n\t\tState: schemahcl.New(append(specOptions,\n\t\t\tschemahcl.WithTypes(\"table.column.type\", TypeRegistry.Specs()),\n\t\t\tschemahcl.WithTypes(\"view.column.type\", TypeRegistry.Specs()),\n\t\t\tschemahcl.WithTypes(\"materialized.column.type\", TypeRegistry.Specs()),\n\t\t\tschemahcl.WithScopedEnums(\"view.check_option\", schema.ViewCheckOptionLocal, schema.ViewCheckOptionCascaded),\n\t\t\tschemahcl.WithScopedEnums(\"table.index.type\", IndexTypeBTree, IndexTypeBRIN, IndexTypeHash, IndexTypeGIN, IndexTypeGiST, \"GiST\", IndexTypeSPGiST, \"SPGiST\"),\n\t\t\tschemahcl.WithScopedEnums(\"table.partition.type\", PartitionTypeRange, PartitionTypeList, PartitionTypeHash),\n\t\t\tschemahcl.WithScopedEnums(\"table.column.identity.generated\", GeneratedTypeAlways, GeneratedTypeByDefault),\n\t\t\tschemahcl.WithScopedEnums(\"table.column.as.type\", \"STORED\"),\n\t\t\tschemahcl.WithScopedEnums(\"table.foreign_key.on_update\", specutil.ReferenceVars...),\n\t\t\tschemahcl.WithScopedEnums(\"table.foreign_key.on_delete\", specutil.ReferenceVars...),\n\t\t\tschemahcl.WithScopedEnums(\"table.index.on.ops\", func() (ops []string) {\n\t\t\t\tfor _, op := range postgresop.Classes {\n\t\t\t\t\tops = append(ops, op.Name)\n\t\t\t\t}\n\t\t\t\treturn ops\n\t\t\t}()...))...,\n\t\t),\n\t}\n\t// MarshalHCL marshals v into an Atlas HCL DDL document.\n\tMarshalHCL = schemahcl.MarshalerFunc(codec.MarshalSpec)\n\t// EvalHCL implements the schemahcl.Evaluator interface.\n\tEvalHCL = schemahcl.EvalFunc(codec.Eval)\n\t// EvalHCLBytes is a helper that evaluates an HCL document from a byte slice instead\n\t// of from an hclparse.Parser instance.\n\tEvalHCLBytes = specutil.HCLBytesFunc(codec)\n)\n\n// convertTable converts a sqlspec.Table to a schema.Table. Table conversion is done without converting\n// ForeignKeySpecs into ForeignKeys, as the target tables do not necessarily exist in the schema\n// at this point. Instead, the linking is done by the convertSchema function.\nfunc convertTable(spec *sqlspec.Table, parent *schema.Schema) (*schema.Table, error) {\n\tt, err := specutil.Table(spec, parent, convertColumn, convertPK, convertIndex, specutil.Check)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := convertUnique(spec.Extra, t); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := convertExclude(spec.Extra, t); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := convertPartition(spec.Extra, t); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := convertTableAttrs(spec, t); err != nil {\n\t\treturn nil, err\n\t}\n\treturn t, nil\n}\n\n// convertView converts a sqlspec.View to a schema.View.\nfunc convertView(spec *sqlspec.View, parent *schema.Schema) (*schema.View, error) {\n\tv, err := specutil.View(\n\t\tspec, parent,\n\t\tfunc(c *sqlspec.Column, _ *schema.View) (*schema.Column, error) {\n\t\t\treturn specutil.Column(c, convertColumnType)\n\t\t},\n\t\tfunc(i *sqlspec.Index, v *schema.View) (*schema.Index, error) {\n\t\t\tidx, err := convertIndex(i, v.AsTable())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tidx.Table, idx.View = nil, v\n\t\t\treturn idx, nil\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn v, nil\n}\n\n// convertUnique converts the unique constraints into indexes.\nfunc convertUnique(spec schemahcl.Resource, t *schema.Table) error {\n\trs := spec.Resources(\"unique\")\n\tfor _, r := range rs {\n\t\tvar sx sqlspec.Index\n\t\tif err := r.As(&sx); err != nil {\n\t\t\treturn fmt.Errorf(\"parse %s.unique constraint: %w\", t.Name, err)\n\t\t}\n\t\tidx, err := convertIndex(&sx, t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tidx.SetUnique(true).AddAttrs(UniqueConstraint(sx.Name))\n\t\tt.AddIndexes(idx)\n\t}\n\treturn nil\n}\n\n// convertPartition converts and appends the partition block into the table attributes if exists.\nfunc convertPartition(spec schemahcl.Resource, table *schema.Table) error {\n\tr, ok := spec.Resource(\"partition\")\n\tif !ok {\n\t\treturn nil\n\t}\n\tvar p struct {\n\t\tType    string           `spec:\"type\"`\n\t\tColumns []*schemahcl.Ref `spec:\"columns\"`\n\t\tParts   []*struct {\n\t\t\tExpr   string         `spec:\"expr\"`\n\t\t\tColumn *schemahcl.Ref `spec:\"column\"`\n\t\t} `spec:\"by\"`\n\t}\n\tif err := r.As(&p); err != nil {\n\t\treturn fmt.Errorf(\"parsing %s.partition: %w\", table.Name, err)\n\t}\n\tif p.Type == \"\" {\n\t\treturn fmt.Errorf(\"missing attribute %s.partition.type\", table.Name)\n\t}\n\tkey := &Partition{T: p.Type}\n\tswitch n, m := len(p.Columns), len(p.Parts); {\n\tcase n == 0 && m == 0:\n\t\treturn fmt.Errorf(\"missing columns or expressions for %s.partition\", table.Name)\n\tcase n > 0 && m > 0:\n\t\treturn fmt.Errorf(`multiple definitions for %s.partition, use \"columns\" or \"by\"`, table.Name)\n\tcase n > 0:\n\t\tfor _, r := range p.Columns {\n\t\t\tc, err := specutil.ColumnByRef(table, r)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tkey.Parts = append(key.Parts, &PartitionPart{C: c})\n\t\t}\n\tcase m > 0:\n\t\tfor i, p := range p.Parts {\n\t\t\tswitch {\n\t\t\tcase p.Column == nil && p.Expr == \"\":\n\t\t\t\treturn fmt.Errorf(\"missing column or expression for %s.partition.by at position %d\", table.Name, i)\n\t\t\tcase p.Column != nil && p.Expr != \"\":\n\t\t\t\treturn fmt.Errorf(\"multiple definitions for  %s.partition.by at position %d\", table.Name, i)\n\t\t\tcase p.Column != nil:\n\t\t\t\tc, err := specutil.ColumnByRef(table, p.Column)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tkey.Parts = append(key.Parts, &PartitionPart{C: c})\n\t\t\tcase p.Expr != \"\":\n\t\t\t\tkey.Parts = append(key.Parts, &PartitionPart{X: &schema.RawExpr{X: p.Expr}})\n\t\t\t}\n\t\t}\n\t}\n\ttable.AddAttrs(key)\n\treturn nil\n}\n\n// fromPartition returns the resource spec for representing the partition block.\nfunc fromPartition(p Partition) *schemahcl.Resource {\n\tkey := &schemahcl.Resource{\n\t\tType: \"partition\",\n\t\tAttrs: []*schemahcl.Attr{\n\t\t\tspecutil.VarAttr(\"type\", strings.ToUpper(specutil.Var(p.T))),\n\t\t},\n\t}\n\tcolumns, ok := func() ([]*schemahcl.Ref, bool) {\n\t\tparts := make([]*schemahcl.Ref, 0, len(p.Parts))\n\t\tfor _, p := range p.Parts {\n\t\t\tif p.C == nil {\n\t\t\t\treturn nil, false\n\t\t\t}\n\t\t\tparts = append(parts, specutil.ColumnRef(p.C.Name))\n\t\t}\n\t\treturn parts, true\n\t}()\n\tif ok {\n\t\tkey.Attrs = append(key.Attrs, schemahcl.RefsAttr(\"columns\", columns...))\n\t\treturn key\n\t}\n\tfor _, p := range p.Parts {\n\t\tpart := &schemahcl.Resource{Type: \"by\"}\n\t\tswitch {\n\t\tcase p.C != nil:\n\t\t\tpart.Attrs = append(part.Attrs, schemahcl.RefAttr(\"column\", specutil.ColumnRef(p.C.Name)))\n\t\tcase p.X != nil:\n\t\t\tpart.Attrs = append(part.Attrs, schemahcl.StringAttr(\"expr\", p.X.(*schema.RawExpr).X))\n\t\t}\n\t\tkey.Children = append(key.Children, part)\n\t}\n\treturn key\n}\n\n// convertColumn converts a sqlspec.Column into a schema.Column.\nfunc convertColumn(spec *sqlspec.Column, _ *schema.Table) (*schema.Column, error) {\n\tif err := fixDefaultQuotes(spec); err != nil {\n\t\treturn nil, err\n\t}\n\tc, err := specutil.Column(spec, convertColumnType)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif r, ok := spec.Extra.Resource(\"identity\"); ok {\n\t\tid, err := convertIdentity(r)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tc.Attrs = append(c.Attrs, id)\n\t}\n\tif err := specutil.ConvertGenExpr(spec.Remain(), c, generatedType); err != nil {\n\t\treturn nil, err\n\t}\n\treturn c, nil\n}\n\nfunc convertIdentity(r *schemahcl.Resource) (*Identity, error) {\n\tvar spec struct {\n\t\tGeneration string `spec:\"generated\"`\n\t\tStart      int64  `spec:\"start\"`\n\t\tIncrement  int64  `spec:\"increment\"`\n\t}\n\tif err := r.As(&spec); err != nil {\n\t\treturn nil, err\n\t}\n\tid := &Identity{Generation: specutil.FromVar(spec.Generation), Sequence: &Sequence{}}\n\tif spec.Start != 0 {\n\t\tid.Sequence.Start = spec.Start\n\t}\n\tif spec.Increment != 0 {\n\t\tid.Sequence.Increment = spec.Increment\n\t}\n\treturn id, nil\n}\n\n// fixDefaultQuotes fixes the quotes on the Default field to be single quotes\n// instead of double quotes.\nfunc fixDefaultQuotes(spec *sqlspec.Column) error {\n\tif a, ok := spec.Attr(\"default\"); ok {\n\t\tif a.V.Type() != cty.String {\n\t\t\treturn nil\n\t\t}\n\t\tif s := a.V.AsString(); sqlx.IsQuoted(s, '\"') {\n\t\t\tuq, err := strconv.Unquote(s)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ts = \"'\" + uq + \"'\"\n\t\t\ta.V = cty.StringVal(s)\n\t\t}\n\t}\n\treturn nil\n}\n\n// convertPK converts a sqlspec.PrimaryKey into a schema.Index.\nfunc convertPK(spec *sqlspec.PrimaryKey, parent *schema.Table) (*schema.Index, error) {\n\tidx, err := specutil.PrimaryKey(spec, parent)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err := convertIndexPK(spec, parent, idx); err != nil {\n\t\treturn nil, err\n\t}\n\treturn idx, nil\n}\n\n// convertIndex converts a sqlspec.Index into a schema.Index.\nfunc convertIndex(spec *sqlspec.Index, t *schema.Table) (*schema.Index, error) {\n\tidx, err := specutil.Index(spec, t, convertPart)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif attr, ok := spec.Attr(\"type\"); ok {\n\t\tt, err := attr.String()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tidx.Attrs = append(idx.Attrs, &IndexType{T: strings.ToUpper(t)})\n\t}\n\tif attr, ok := spec.Attr(\"where\"); ok {\n\t\tp, err := attr.String()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tidx.Attrs = append(idx.Attrs, &IndexPredicate{P: p})\n\t}\n\tif attr, ok := spec.Attr(\"nulls_distinct\"); ok {\n\t\tv, err := attr.Bool()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tidx.Attrs = append(idx.Attrs, &IndexNullsDistinct{V: v})\n\t}\n\tif err := convertIndexPK(spec, t, idx); err != nil {\n\t\treturn nil, err\n\t}\n\treturn idx, nil\n}\n\n// convertIndexPK converts the index parameters shared between primary and secondary indexes.\nfunc convertIndexPK(spec specutil.Attrer, t *schema.Table, idx *schema.Index) error {\n\tif attr, ok := spec.Attr(\"page_per_range\"); ok {\n\t\tp, err := attr.Int64()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tidx.Attrs = append(idx.Attrs, &IndexStorageParams{PagesPerRange: p})\n\t}\n\tif attr, ok := spec.Attr(\"include\"); ok {\n\t\trefs, err := attr.Refs()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(refs) == 0 {\n\t\t\treturn fmt.Errorf(\"unexpected empty INCLUDE in index %q definition\", idx.Name)\n\t\t}\n\t\tinclude := make([]*schema.Column, len(refs))\n\t\tfor i, r := range refs {\n\t\t\tif include[i], err = specutil.ColumnByRef(t, r); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tidx.Attrs = append(idx.Attrs, &IndexInclude{Columns: include})\n\t}\n\treturn nil\n}\n\nfunc convertPart(spec *sqlspec.IndexPart, part *schema.IndexPart) error {\n\tswitch opc, ok := spec.Attr(\"ops\"); {\n\tcase !ok:\n\tcase opc.IsRawExpr():\n\t\texpr, err := opc.RawExpr()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tvar op IndexOpClass\n\t\tif err := op.UnmarshalText([]byte(expr.X)); err != nil {\n\t\t\treturn fmt.Errorf(\"unexpected index.on.ops expression %q: %w\", expr.X, err)\n\t\t}\n\t\tif op.Name != \"\" {\n\t\t\tpart.Attrs = append(part.Attrs, &op)\n\t\t}\n\tcase opc.IsRef():\n\t\tname, err := opc.Ref()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tpart.Attrs = append(part.Attrs, &IndexOpClass{Name: name})\n\tdefault:\n\t\tname, err := opc.String()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tpart.Attrs = append(part.Attrs, &IndexOpClass{Name: name})\n\t}\n\t// The following attributes are mutually exclusive.\n\tif nulls, ok := spec.Attr(\"nulls_last\"); ok {\n\t\tb, err := nulls.Bool()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif b {\n\t\t\tat := sqlx.AttrOr(part.Attrs, &IndexColumnProperty{})\n\t\t\tat.NullsLast = true\n\t\t\tschema.ReplaceOrAppend(&part.Attrs, at)\n\t\t}\n\t}\n\tif nulls, ok := spec.Attr(\"nulls_first\"); ok {\n\t\tb, err := nulls.Bool()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif b {\n\t\t\tat := sqlx.AttrOr(part.Attrs, &IndexColumnProperty{})\n\t\t\tat.NullsFirst = true\n\t\t\tschema.ReplaceOrAppend(&part.Attrs, at)\n\t\t}\n\t}\n\treturn nil\n}\n\nconst defaultTimePrecision = 6\n\n// convertColumnType converts a sqlspec.Column into a concrete Postgres schema.Type.\nfunc convertColumnType(spec *sqlspec.Column) (schema.Type, error) {\n\ttyp, err := TypeRegistry.Type(spec.Type, spec.Extra.Attrs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Handle default values for time precision types.\n\tif t, ok := typ.(*schema.TimeType); ok && strings.HasPrefix(t.T, \"time\") {\n\t\tif _, ok := attr(spec.Type, \"precision\"); !ok {\n\t\t\tp := defaultTimePrecision\n\t\t\tt.Precision = &p\n\t\t}\n\t}\n\treturn typ, nil\n}\n\n// enumName extracts the name of the referenced Enum from the reference string.\nfunc enumName(ref *schemahcl.Type) (string, error) {\n\ts := strings.Split(ref.T, \"$enum.\")\n\tif len(s) != 2 {\n\t\treturn \"\", fmt.Errorf(\"postgres: failed to extract enum name from %q\", ref.T)\n\t}\n\treturn s[1], nil\n}\n\n// schemaSpec converts from a concrete Postgres schema to Atlas specification.\nfunc schemaSpec(s *schema.Schema) (*doc, []*schema.Trigger, error) {\n\tspec, err := specutil.FromSchema(s, specFuncs)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\td := &doc{\n\t\tTables:       spec.Tables,\n\t\tViews:        spec.Views,\n\t\tMaterialized: spec.Materialized,\n\t\tFuncs:        spec.Funcs,\n\t\tProcs:        spec.Procs,\n\t\tSchemas:      []*sqlspec.Schema{spec.Schema},\n\t\tEnums:        make([]*enum, 0, len(s.Objects)),\n\t\tDomains:      make([]*domain, 0, len(s.Objects)),\n\t\tComposites:   make([]*composite, 0, len(s.Objects)),\n\t}\n\tif err := objectSpec(d, spec, s); err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn d, spec.Triggers, nil\n}\n\n// tableSpec converts from a concrete Postgres sqlspec.Table to a schema.Table.\nfunc tableSpec(t *schema.Table) (*sqlspec.Table, error) {\n\tspec, err := specutil.FromTable(\n\t\tt,\n\t\ttableColumnSpec,\n\t\tpkSpec,\n\t\tindexSpec,\n\t\tspecutil.FromForeignKey,\n\t\tspecutil.FromCheck,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tidxs := make([]*sqlspec.Index, 0, len(spec.Indexes))\n\tfor i, idx1 := range spec.Indexes {\n\t\tif len(t.Indexes) <= i || t.Indexes[i].Name != idx1.Name {\n\t\t\treturn nil, fmt.Errorf(\"unexpected spec index %q was not found in table %q\", idx1.Name, t.Name)\n\t\t}\n\t\tif c, ok := uniqueConst(t.Indexes[i].Attrs); ok && c.N != \"\" {\n\t\t\tspec.Extra.Children = append(spec.Extra.Children, &schemahcl.Resource{\n\t\t\t\tType: \"unique\",\n\t\t\t\tName: c.N,\n\t\t\t\tAttrs: append(\n\t\t\t\t\t[]*schemahcl.Attr{schemahcl.RefsAttr(\"columns\", idx1.Columns...)},\n\t\t\t\t\tidx1.Extra.Attrs...,\n\t\t\t\t),\n\t\t\t})\n\t\t} else if ex, ok := excludeConst(t.Indexes[i].Attrs); !ok {\n\t\t\tidxs = append(idxs, idx1)\n\t\t} else if err := excludeSpec(spec, idx1, t.Indexes[i], ex); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tspec.Indexes = idxs\n\tif p := (Partition{}); sqlx.Has(t.Attrs, &p) {\n\t\tspec.Extra.Children = append(spec.Extra.Children, fromPartition(p))\n\t}\n\ttableAttrsSpec(t, spec)\n\treturn spec, nil\n}\n\n// viewSpec converts from a concrete PostgreSQL schema.View to a sqlspec.View.\nfunc viewSpec(view *schema.View) (*sqlspec.View, error) {\n\tspec, err := specutil.FromView(\n\t\tview,\n\t\tfunc(c *schema.Column, _ *schema.View) (*sqlspec.Column, error) {\n\t\t\treturn specutil.FromColumn(c, columnTypeSpec)\n\t\t},\n\t\tindexSpec,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn spec, nil\n}\n\nfunc pkSpec(idx *schema.Index) (*sqlspec.PrimaryKey, error) {\n\tspec, err := specutil.FromPrimaryKey(idx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tspec.Extra.Attrs = indexPKSpec(idx, spec.Extra.Attrs)\n\treturn spec, nil\n}\n\nfunc indexSpec(idx *schema.Index) (*sqlspec.Index, error) {\n\tspec, err := specutil.FromIndex(idx, partAttr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Avoid printing the index type if it is the default.\n\tif i := (IndexType{}); sqlx.Has(idx.Attrs, &i) && strings.ToUpper(i.T) != IndexTypeBTree {\n\t\tvar attr *schemahcl.Attr\n\t\tswitch strings.ToUpper(i.T) {\n\t\tcase IndexTypeBRIN, IndexTypeHash, IndexTypeGIN, IndexTypeGiST, IndexTypeSPGiST:\n\t\t\tattr = specutil.VarAttr(\"type\", strings.ToUpper(i.T))\n\t\tdefault:\n\t\t\tattr = schemahcl.StringAttr(\"type\", i.T)\n\t\t}\n\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, attr)\n\t}\n\tif i := (IndexPredicate{}); sqlx.Has(idx.Attrs, &i) && i.P != \"\" {\n\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, specutil.VarAttr(\"where\", strconv.Quote(i.P)))\n\t}\n\tif i := (IndexNullsDistinct{}); sqlx.Has(idx.Attrs, &i) && !i.V {\n\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.BoolAttr(\"nulls_distinct\", i.V))\n\t}\n\tspec.Extra.Attrs = indexPKSpec(idx, spec.Extra.Attrs)\n\treturn spec, nil\n}\n\nfunc indexPKSpec(idx *schema.Index, attrs []*schemahcl.Attr) []*schemahcl.Attr {\n\tif i := (IndexInclude{}); sqlx.Has(idx.Attrs, &i) && len(i.Columns) > 0 {\n\t\trefs := make([]*schemahcl.Ref, 0, len(i.Columns))\n\t\tfor _, c := range i.Columns {\n\t\t\trefs = append(refs, specutil.ColumnRef(c.Name))\n\t\t}\n\t\tattrs = append(attrs, schemahcl.RefsAttr(\"include\", refs...))\n\t}\n\tif p, ok := indexStorageParams(idx.Attrs); ok {\n\t\tattrs = append(attrs, schemahcl.Int64Attr(\"page_per_range\", p.PagesPerRange))\n\t}\n\treturn attrs\n}\n\nfunc partAttr(idx *schema.Index, part *schema.IndexPart, spec *sqlspec.IndexPart) error {\n\tif op := (IndexOpClass{}); sqlx.Has(part.Attrs, &op) {\n\t\tswitch d, err := op.DefaultFor(idx, part); {\n\t\tcase err != nil:\n\t\t\treturn err\n\t\tcase d:\n\t\tcase len(op.Params) > 0:\n\t\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.RawAttr(\"ops\", op.String()))\n\t\tcase postgresop.HasClass(op.String()):\n\t\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, specutil.VarAttr(\"ops\", op.String()))\n\t\tdefault:\n\t\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.StringAttr(\"ops\", op.String()))\n\t\t}\n\t}\n\tif nulls := (IndexColumnProperty{}); sqlx.Has(part.Attrs, &nulls) {\n\t\tswitch {\n\t\tcase part.Desc && nulls.NullsLast:\n\t\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.BoolAttr(\"nulls_last\", true))\n\t\tcase !part.Desc && nulls.NullsFirst:\n\t\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, schemahcl.BoolAttr(\"nulls_first\", true))\n\t\t}\n\t}\n\treturn nil\n}\n\n// tableColumnSpec converts from a concrete Postgres schema.Column into a sqlspec.Column.\nfunc tableColumnSpec(c *schema.Column, _ *schema.Table) (*sqlspec.Column, error) {\n\ts, err := specutil.FromColumn(c, columnTypeSpec)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif i := (&Identity{}); sqlx.Has(c.Attrs, i) {\n\t\ts.Extra.Children = append(s.Extra.Children, fromIdentity(i))\n\t}\n\tif x := (schema.GeneratedExpr{}); sqlx.Has(c.Attrs, &x) {\n\t\ts.Extra.Children = append(s.Extra.Children, specutil.FromGenExpr(x, generatedType))\n\t}\n\treturn s, nil\n}\n\n// fromIdentity returns the resource spec for representing the identity attributes.\nfunc fromIdentity(i *Identity) *schemahcl.Resource {\n\tid := &schemahcl.Resource{\n\t\tType: \"identity\",\n\t\tAttrs: []*schemahcl.Attr{\n\t\t\tspecutil.VarAttr(\"generated\", strings.ToUpper(specutil.Var(i.Generation))),\n\t\t},\n\t}\n\tif s := i.Sequence; s != nil {\n\t\tif s.Start != 1 {\n\t\t\tid.Attrs = append(id.Attrs, schemahcl.Int64Attr(\"start\", s.Start))\n\t\t}\n\t\tif s.Increment != 1 {\n\t\t\tid.Attrs = append(id.Attrs, schemahcl.Int64Attr(\"increment\", s.Increment))\n\t\t}\n\t}\n\treturn id\n}\n\n// columnTypeSpec converts from a concrete Postgres schema.Type into sqlspec.Column Type.\nfunc columnTypeSpec(t schema.Type) (*sqlspec.Column, error) {\n\tswitch o := t.(type) {\n\tcase *schema.EnumType:\n\t\treturn &sqlspec.Column{\n\t\t\tType: &schemahcl.Type{\n\t\t\t\tIsRef: true,\n\t\t\t\tT:     specutil.ObjectRef(o.Schema, o).V},\n\t\t}, nil\n\tcase *CompositeType:\n\t\treturn &sqlspec.Column{\n\t\t\tType: &schemahcl.Type{\n\t\t\t\tIsRef: true,\n\t\t\t\tT:     specutil.ObjectRef(o.Schema, o).V},\n\t\t}, nil\n\tcase *DomainType:\n\t\treturn &sqlspec.Column{\n\t\t\tType: &schemahcl.Type{\n\t\t\t\tIsRef: true,\n\t\t\t\tT:     specutil.ObjectRef(o.Schema, o).V},\n\t\t}, nil\n\tdefault:\n\t\tst, err := TypeRegistry.Convert(t)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &sqlspec.Column{Type: st}, nil\n\t}\n}\n\n// TypeRegistry contains the supported TypeSpecs for the Postgres driver.\nvar TypeRegistry = schemahcl.NewRegistry(\n\tschemahcl.WithSpecFunc(typeSpec),\n\tschemahcl.WithParser(ParseType),\n\tschemahcl.WithSpecs(\n\t\tschemahcl.NewTypeSpec(TypeBit, schemahcl.WithAttributes(&schemahcl.TypeAttr{Name: \"len\", Kind: reflect.Int64})),\n\t\tschemahcl.AliasTypeSpec(\"bit_varying\", TypeBitVar, schemahcl.WithAttributes(&schemahcl.TypeAttr{Name: \"len\", Kind: reflect.Int64})),\n\t\tschemahcl.NewTypeSpec(TypeVarChar, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.AliasTypeSpec(\"character_varying\", TypeCharVar, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeChar, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeCharacter, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeBPChar),\n\t\tschemahcl.NewTypeSpec(TypeInt2),\n\t\tschemahcl.NewTypeSpec(TypeInt4),\n\t\tschemahcl.NewTypeSpec(TypeInt8),\n\t\tschemahcl.NewTypeSpec(TypeInt),\n\t\tschemahcl.NewTypeSpec(TypeInteger),\n\t\tschemahcl.NewTypeSpec(TypeSmallInt),\n\t\tschemahcl.NewTypeSpec(TypeBigInt),\n\t\tschemahcl.NewTypeSpec(TypeText),\n\t\tschemahcl.NewTypeSpec(TypeBoolean),\n\t\tschemahcl.NewTypeSpec(TypeBool),\n\t\tschemahcl.NewTypeSpec(TypeBytea),\n\t\tschemahcl.NewTypeSpec(TypeCIDR),\n\t\tschemahcl.NewTypeSpec(TypeInet),\n\t\tschemahcl.NewTypeSpec(TypeMACAddr),\n\t\tschemahcl.NewTypeSpec(TypeMACAddr8),\n\t\tschemahcl.NewTypeSpec(TypeCircle),\n\t\tschemahcl.NewTypeSpec(TypeLine),\n\t\tschemahcl.NewTypeSpec(TypeLseg),\n\t\tschemahcl.NewTypeSpec(TypeBox),\n\t\tschemahcl.NewTypeSpec(TypePath),\n\t\tschemahcl.NewTypeSpec(TypePoint),\n\t\tschemahcl.NewTypeSpec(TypePolygon),\n\t\tschemahcl.NewTypeSpec(TypeDate),\n\t\tschemahcl.NewTypeSpec(TypeTime, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr()), formatTime()),\n\t\tschemahcl.NewTypeSpec(TypeTimeTZ, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr()), formatTime()),\n\t\tschemahcl.NewTypeSpec(TypeTimestampTZ, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr()), formatTime()),\n\t\tschemahcl.NewTypeSpec(TypeTimestamp, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr()), formatTime()),\n\t\tschemahcl.AliasTypeSpec(\"double_precision\", TypeDouble),\n\t\tschemahcl.NewTypeSpec(TypeReal),\n\t\tschemahcl.NewTypeSpec(TypeFloat, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeFloat8),\n\t\tschemahcl.NewTypeSpec(TypeFloat4),\n\t\tschemahcl.NewTypeSpec(TypeNumeric, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr(), schemahcl.ScaleTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeDecimal, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr(), schemahcl.ScaleTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeSmallSerial),\n\t\tschemahcl.NewTypeSpec(TypeSerial),\n\t\tschemahcl.NewTypeSpec(TypeBigSerial),\n\t\tschemahcl.NewTypeSpec(TypeSerial2),\n\t\tschemahcl.NewTypeSpec(TypeSerial4),\n\t\tschemahcl.NewTypeSpec(TypeSerial8),\n\t\tschemahcl.NewTypeSpec(TypeXML),\n\t\tschemahcl.NewTypeSpec(TypeJSON),\n\t\tschemahcl.NewTypeSpec(TypeJSONB),\n\t\tschemahcl.NewTypeSpec(TypeUUID),\n\t\tschemahcl.NewTypeSpec(TypeMoney),\n\t\tschemahcl.NewTypeSpec(TypeTSVector),\n\t\tschemahcl.NewTypeSpec(TypeTSQuery),\n\t\tschemahcl.NewTypeSpec(TypeInt4Range),\n\t\tschemahcl.NewTypeSpec(TypeInt4MultiRange),\n\t\tschemahcl.NewTypeSpec(TypeInt8Range),\n\t\tschemahcl.NewTypeSpec(TypeInt8MultiRange),\n\t\tschemahcl.NewTypeSpec(TypeNumRange),\n\t\tschemahcl.NewTypeSpec(TypeNumMultiRange),\n\t\tschemahcl.NewTypeSpec(TypeTSRange),\n\t\tschemahcl.NewTypeSpec(TypeTSMultiRange),\n\t\tschemahcl.NewTypeSpec(TypeTSTZRange),\n\t\tschemahcl.NewTypeSpec(TypeTSTZMultiRange),\n\t\tschemahcl.NewTypeSpec(TypeDateRange),\n\t\tschemahcl.NewTypeSpec(TypeDateMultiRange),\n\t\tschemahcl.NewTypeSpec(\"hstore\"),\n\t\tschemahcl.NewTypeSpec(TypeXID),\n\t\tschemahcl.NewTypeSpec(TypeXID8),\n\t),\n\t// PostgreSQL internal, pseudo, and special types.\n\tschemahcl.WithSpecs(func() (specs []*schemahcl.TypeSpec) {\n\t\tfor _, t := range []string{\n\t\t\ttypeOID, typeRegClass, typeRegCollation, typeRegConfig, typeRegDictionary, typeRegNamespace,\n\t\t\ttypeName, typeRegOper, typeRegOperator, typeRegProc, typeRegProcedure, typeRegRole, typeRegType,\n\t\t\ttypeAny, typeAnyElement, typeAnyArray, typeAnyNonArray, typeAnyEnum, typeInternal, typeRecord,\n\t\t\ttypeTrigger, typeEventTrigger, typeVoid, typeUnknown,\n\t\t} {\n\t\t\tspecs = append(specs, schemahcl.NewTypeSpec(t))\n\t\t}\n\t\treturn specs\n\t}()...),\n\tschemahcl.WithSpecs(func() (specs []*schemahcl.TypeSpec) {\n\t\topts := []schemahcl.TypeSpecOption{\n\t\t\tschemahcl.WithToSpec(func(t schema.Type) (*schemahcl.Type, error) {\n\t\t\t\ti, ok := t.(*IntervalType)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, fmt.Errorf(\"postgres: unexpected interval type %T\", t)\n\t\t\t\t}\n\t\t\t\tspec := &schemahcl.Type{T: TypeInterval}\n\t\t\t\tif i.F != \"\" {\n\t\t\t\t\tspec.T = specutil.Var(strings.ToLower(i.F))\n\t\t\t\t}\n\t\t\t\tif p := i.Precision; p != nil && *p != defaultTimePrecision {\n\t\t\t\t\tspec.Attrs = []*schemahcl.Attr{schemahcl.IntAttr(\"precision\", *p)}\n\t\t\t\t}\n\t\t\t\treturn spec, nil\n\t\t\t}),\n\t\t\tschemahcl.WithFromSpec(func(t *schemahcl.Type) (schema.Type, error) {\n\t\t\t\ti := &IntervalType{T: TypeInterval}\n\t\t\t\tif t.T != TypeInterval {\n\t\t\t\t\ti.F = specutil.FromVar(t.T)\n\t\t\t\t}\n\t\t\t\tif a, ok := attr(t, \"precision\"); ok {\n\t\t\t\t\tp, err := a.Int()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, fmt.Errorf(`postgres: parsing attribute \"precision\": %w`, err)\n\t\t\t\t\t}\n\t\t\t\t\tif p != defaultTimePrecision {\n\t\t\t\t\t\ti.Precision = &p\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn i, nil\n\t\t\t}),\n\t\t}\n\t\tfor _, f := range []string{\"interval\", \"second\", \"day to second\", \"hour to second\", \"minute to second\"} {\n\t\t\tspecs = append(specs, schemahcl.NewTypeSpec(specutil.Var(f), append(opts, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr()))...))\n\t\t}\n\t\tfor _, f := range []string{\"year\", \"month\", \"day\", \"hour\", \"minute\", \"year to month\", \"day to hour\", \"day to minute\", \"hour to minute\"} {\n\t\t\tspecs = append(specs, schemahcl.NewTypeSpec(specutil.Var(f), opts...))\n\t\t}\n\t\treturn specs\n\t}()...),\n)\n\nfunc attr(typ *schemahcl.Type, key string) (*schemahcl.Attr, bool) {\n\tfor _, a := range typ.Attrs {\n\t\tif a.K == key {\n\t\t\treturn a, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\nfunc typeSpec(t schema.Type) (*schemahcl.Type, error) {\n\tif t, ok := t.(*schema.TimeType); ok && t.T != TypeDate {\n\t\tspec := &schemahcl.Type{T: timeAlias(t.T)}\n\t\tif p := t.Precision; p != nil && *p != defaultTimePrecision {\n\t\t\tspec.Attrs = []*schemahcl.Attr{schemahcl.IntAttr(\"precision\", *p)}\n\t\t}\n\t\treturn spec, nil\n\t}\n\ts, err := FormatType(t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &schemahcl.Type{T: s}, nil\n}\n\n// formatTime overrides the default printing logic done by schemahcl.hclType.\nfunc formatTime() schemahcl.TypeSpecOption {\n\treturn schemahcl.WithTypeFormatter(func(t *schemahcl.Type) (string, error) {\n\t\ta, ok := attr(t, \"precision\")\n\t\tif !ok {\n\t\t\treturn t.T, nil\n\t\t}\n\t\tp, err := a.Int()\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(`postgres: parsing attribute \"precision\": %w`, err)\n\t\t}\n\t\treturn FormatType(&schema.TimeType{T: t.T, Precision: &p})\n\t})\n}\n\n// generatedType returns the default and only type for a generated column.\nfunc generatedType(string) string { return \"STORED\" }\n"
  },
  {
    "path": "sql/postgres/sqlspec_oss_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage postgres\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/internal/spectest\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSQLSpec(t *testing.T) {\n\tf := `\nschema \"schema\" {\n}\n\ntable \"table\" {\n\tschema = schema.schema\n\tcolumn \"col\" {\n\t\ttype = integer\n\t\tcomment = \"column comment\"\n\t}\n\tcolumn \"age\" {\n\t\ttype = integer\n\t}\n\tcolumn \"price\" {\n\t\ttype = int\n\t}\n\tcolumn \"account_name\" {\n\t\ttype = varchar(32)\n\t}\n\tcolumn \"varchar_length_is_not_required\" {\n\t\ttype = varchar\n\t}\n\tcolumn \"character_varying_length_is_not_required\" {\n\t\ttype = character_varying\n\t}\n\tcolumn \"tags\" {\n\t\ttype = hstore\n\t}\n\tcolumn \"created_at\" {\n\t\ttype    = timestamp(4)\n\t\tdefault = sql(\"current_timestamp(4)\")\n\t}\n\tcolumn \"updated_at\" {\n\t\ttype    = time\n\t\tdefault = sql(\"current_time\")\n\t}\n\tprimary_key {\n\t\tcolumns = [table.table.column.col]\n\t}\n\tindex \"index\" {\n\t\ttype = HASH\n\t\tunique = true\n\t\tcolumns = [\n\t\t\ttable.table.column.col,\n\t\t\ttable.table.column.age,\n\t\t]\n\t\twhere = \"active\"\n\t\tcomment = \"index comment\"\n\t}\n\tindex \"index_hnsw\" {\n\t\ttype = \"HNSW\"\n\t\tcolumns = [\n\t\t\ttable.table.column.col,\n\t\t\ttable.table.column.age,\n\t\t]\n\t}\n\tforeign_key \"accounts\" {\n\t\tcolumns = [\n\t\t\ttable.table.column.account_name,\n\t\t]\n\t\tref_columns = [\n\t\t\ttable.accounts.column.name,\n\t\t]\n\t\ton_delete = SET_NULL\n\t}\n\tcheck \"positive price\" {\n\t\texpr = \"price > 0\"\n\t}\n\tcomment = \"table comment\"\n}\n\ntable \"accounts\" {\n\tschema = schema.schema\n\tcolumn \"name\" {\n\t\ttype = varchar(32)\n\t}\n\tcolumn \"type\" {\n\t\ttype = enum.account_type\n\t}\n\tprimary_key {\n\t\tcolumns = [table.accounts.column.name]\n\t}\n}\n\nenum \"account_type\" {\n\tschema = schema.schema\n\tvalues = [\"private\", \"business\"]\n}\n`\n\tvar s schema.Schema\n\terr := EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\texp := schema.New(\"schema\")\n\texp.AddObjects(&schema.EnumType{T: \"account_type\", Values: []string{\"private\", \"business\"}, Schema: exp})\n\texp.Tables = []*schema.Table{\n\t\t{\n\t\t\tName:   \"table\",\n\t\t\tSchema: exp,\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{\n\t\t\t\t\tName: \"col\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\t\tT: \"integer\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t&schema.Comment{Text: \"column comment\"},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"age\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\t\tT: \"integer\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"price\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\t\tT: TypeInt,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"account_name\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.StringType{\n\t\t\t\t\t\t\tT:    \"varchar\",\n\t\t\t\t\t\t\tSize: 32,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"varchar_length_is_not_required\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.StringType{\n\t\t\t\t\t\t\tT:    \"varchar\",\n\t\t\t\t\t\t\tSize: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"character_varying_length_is_not_required\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.StringType{\n\t\t\t\t\t\t\tT:    \"character varying\",\n\t\t\t\t\t\t\tSize: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"tags\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &UserDefinedType{\n\t\t\t\t\t\t\tT: \"hstore\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"created_at\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: typeTime(TypeTimestamp, 4),\n\t\t\t\t\t},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"current_timestamp(4)\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"updated_at\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: typeTime(TypeTime, 6),\n\t\t\t\t\t},\n\t\t\t\t\tDefault: &schema.RawExpr{X: \"current_time\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Check{\n\t\t\t\t\tName: \"positive price\",\n\t\t\t\t\tExpr: \"price > 0\",\n\t\t\t\t},\n\t\t\t\t&schema.Comment{Text: \"table comment\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:   \"accounts\",\n\t\t\tSchema: exp,\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{\n\t\t\t\t\tName: \"name\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.StringType{\n\t\t\t\t\t\t\tT:    \"varchar\",\n\t\t\t\t\t\t\tSize: 32,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"type\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.EnumType{\n\t\t\t\t\t\t\tT:      \"account_type\",\n\t\t\t\t\t\t\tValues: []string{\"private\", \"business\"},\n\t\t\t\t\t\t\tSchema: exp,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\texp.Tables[0].PrimaryKey = &schema.Index{\n\t\tTable: exp.Tables[0],\n\t\tParts: []*schema.IndexPart{\n\t\t\t{SeqNo: 0, C: exp.Tables[0].Columns[0]},\n\t\t},\n\t}\n\texp.Tables[0].Indexes = []*schema.Index{\n\t\t{\n\t\t\tName:   \"index\",\n\t\t\tTable:  exp.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: exp.Tables[0].Columns[0]},\n\t\t\t\t{SeqNo: 1, C: exp.Tables[0].Columns[1]},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Comment{Text: \"index comment\"},\n\t\t\t\t&IndexType{T: IndexTypeHash},\n\t\t\t\t&IndexPredicate{P: \"active\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:  \"index_hnsw\",\n\t\t\tTable: exp.Tables[0],\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: exp.Tables[0].Columns[0]},\n\t\t\t\t{SeqNo: 1, C: exp.Tables[0].Columns[1]},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexType{T: \"HNSW\"},\n\t\t\t},\n\t\t},\n\t}\n\texp.Tables[0].ForeignKeys = []*schema.ForeignKey{\n\t\t{\n\t\t\tSymbol:     \"accounts\",\n\t\t\tTable:      exp.Tables[0],\n\t\t\tColumns:    []*schema.Column{exp.Tables[0].Columns[3]},\n\t\t\tRefTable:   exp.Tables[1],\n\t\t\tRefColumns: []*schema.Column{exp.Tables[1].Columns[0]},\n\t\t\tOnDelete:   schema.SetNull,\n\t\t},\n\t}\n\texp.Tables[1].PrimaryKey = &schema.Index{\n\t\tTable: exp.Tables[1],\n\t\tParts: []*schema.IndexPart{\n\t\t\t{SeqNo: 0, C: exp.Tables[1].Columns[0]},\n\t\t},\n\t}\n\texp.Tables[0].Columns[0].AddIndexes(exp.Tables[0].PrimaryKey)\n\texp.Tables[0].Columns[0].AddIndexes(exp.Tables[0].Indexes...)\n\texp.Tables[0].Columns[1].AddIndexes(exp.Tables[0].Indexes...)\n\texp.Tables[1].Columns[0].AddIndexes(exp.Tables[1].PrimaryKey)\n\texp.Realm = schema.NewRealm(exp)\n\trequire.EqualValues(t, exp, &s)\n}\n\nfunc TestMarshalSpec_Schema(t *testing.T) {\n\ts := schema.New(\"public\").SetComment(\"schema comment\")\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `schema \"public\" {\n  comment = \"schema comment\"\n}\n`, string(buf))\n\n\tr := schema.NewRealm(\n\t\tschema.New(\"s1\").SetComment(\"c1\"),\n\t\tschema.New(\"s2\").SetComment(\"c2\"),\n\t\tschema.New(\"s3\"),\n\t)\n\tbuf, err = MarshalHCL(r)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `schema \"s1\" {\n  comment = \"c1\"\n}\nschema \"s2\" {\n  comment = \"c2\"\n}\nschema \"s3\" {\n}\n`, string(buf))\n}\n\nfunc TestUnmarshalSpec_Schema(t *testing.T) {\n\tvar (\n\t\ts schema.Schema\n\t\tf = `\nschema \"public\" {\n  comment = \"schema comment\"\n}\n`\n\t)\n\trequire.NoError(t, EvalHCLBytes([]byte(f), &s, nil))\n\trequire.Equal(t, \"public\", s.Name)\n\trequire.Len(t, s.Attrs, 1)\n\trequire.Equal(t, \"schema comment\", s.Attrs[0].(*schema.Comment).Text)\n}\n\nfunc TestMarshalViews(t *testing.T) {\n\ts := schema.New(\"public\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t),\n\t\t).\n\t\tAddViews(\n\t\t\tschema.NewView(\"v1\", \"SELECT 1\").\n\t\t\t\tSetCheckOption(schema.ViewCheckOptionLocal),\n\t\t\tschema.NewView(\"v2\", \"SELECT * FROM t2\\n\\tWHERE id IS NOT NULL\"),\n\t\t\tschema.NewView(\"v3\", \"SELECT * FROM t3\\n\\tWHERE id IS NOT NULL\\n\\tORDER BY id\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"id\", \"id\"),\n\t\t\t\t).\n\t\t\t\tSetComment(\"view comment\"),\n\t\t\tschema.NewMaterializedView(\"m1\", \"SELECT * FROM t1\"),\n\t\t)\n\ts.AddViews(\n\t\tschema.NewView(\"v4\", \"SELECT * FROM v2 JOIN t1 USING (id)\").\n\t\t\tAddDeps(\n\t\t\t\ts.Views[1],\n\t\t\t\ts.Tables[0],\n\t\t\t),\n\t\tschema.NewMaterializedView(\"m2\", \"SELECT * FROM t1\").\n\t\t\tAddDeps(\n\t\t\t\ts.Views[1],\n\t\t\t\ts.Views[3],\n\t\t\t\ts.Tables[0],\n\t\t\t),\n\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tf := `table \"t1\" {\n  schema = schema.public\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nview \"v1\" {\n  schema       = schema.public\n  as           = \"SELECT 1\"\n  check_option = LOCAL\n}\nview \"v2\" {\n  schema = schema.public\n  as     = <<-SQL\n  SELECT * FROM t2\n  \tWHERE id IS NOT NULL\n  SQL\n}\nview \"v3\" {\n  schema = schema.public\n  column \"id\" {\n    null = false\n    type = sql(\"id\")\n  }\n  as      = <<-SQL\n  SELECT * FROM t3\n  \tWHERE id IS NOT NULL\n  \tORDER BY id\n  SQL\n  comment = \"view comment\"\n}\nview \"v4\" {\n  schema     = schema.public\n  as         = \"SELECT * FROM v2 JOIN t1 USING (id)\"\n  depends_on = [table.t1, view.v2]\n}\nmaterialized \"m1\" {\n  schema = schema.public\n  as     = \"SELECT * FROM t1\"\n}\nmaterialized \"m2\" {\n  schema     = schema.public\n  as         = \"SELECT * FROM t1\"\n  depends_on = [materialized.m1, table.t1, view.v2]\n}\nschema \"public\" {\n}\n`\n\trequire.Equal(t, f, string(buf))\n}\n\nfunc TestUnmarshalViews(t *testing.T) {\n\tf := `table \"t1\" {\n  schema = schema.public\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nview \"v1\" {\n  schema = schema.public\n  as     = \"SELECT * FROM t2 WHERE id IS NOT NULL\"\n}\nmaterialized \"m1\" {\n  schema = schema.public\n  as     = \"SELECT * FROM t2 WHERE id IS NOT NULL\"\n}\nmaterialized \"m2\" {\n  schema     = schema.public\n  as         = \"SELECT * FROM multi\"\n  depends_on = [view.v1, materialized.m1, table.t1]\n}\nview \"v2\" {\n schema = schema.public\n column \"id\" {\n   null = false\n   type = int\n }\n as      = \"SELECT * FROM t3 WHERE id IS NOT NULL ORDER BY id\"\n comment = \"view comment\"\n}\nview \"v3\" {\n schema       = schema.public\n as           = \"SELECT * FROM v2 JOIN t1 USING (id)\"\n check_option = LOCAL\n depends_on   = [view.v1, table.t1]\n}\n\ntable \"public\" \"t2\" {\n  schema = schema.public\n  column \"id\" {\n    type = int\n  }\n}\n\ntable \"other\" \"t2\" {\n  schema = schema.other\n  column \"id\" {\n    type = int\n  }\n}\n\nview \"public\" \"v4\" {\n  schema = schema.public\n  as     = \"SELECT * FROM public.t2\"\n  depends_on = [table.public.t2]\n}\n\nview \"other\" \"v4\" {\n  schema = schema.other\n  as     = \"SELECT * FROM other.t2\"\n  depends_on = [table.other.t2]\n}\n\nschema \"public\" {}\nschema \"other\" {}\n`\n\tvar (\n\t\tr      schema.Realm\n\t\tgot    schema.Realm\n\t\tpublic = schema.New(\"public\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"t1\").\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t),\n\t\t\t\tschema.NewTable(\"t2\").\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t),\n\t\t\t).\n\t\t\tAddViews(\n\t\t\t\tschema.NewView(\"v1\", \"SELECT * FROM t2 WHERE id IS NOT NULL\"),\n\t\t\t\tschema.NewView(\"v2\", \"SELECT * FROM t3 WHERE id IS NOT NULL ORDER BY id\").\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t).\n\t\t\t\t\tSetComment(\"view comment\"),\n\t\t\t)\n\t\tother = schema.New(\"other\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"t2\").\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t),\n\t\t\t)\n\t)\n\tpublic.AddViews(\n\t\tschema.NewView(\"v3\", \"SELECT * FROM v2 JOIN t1 USING (id)\").\n\t\t\tSetCheckOption(schema.ViewCheckOptionLocal).\n\t\t\tAddDeps(public.Views[0], public.Tables[0]),\n\t\tschema.NewView(\"v4\", \"SELECT * FROM public.t2\").\n\t\t\tAddDeps(public.Tables[1]),\n\t\tschema.NewMaterializedView(\"m1\", \"SELECT * FROM t2 WHERE id IS NOT NULL\"),\n\t)\n\tm1, _ := public.Materialized(\"m1\")\n\tpublic.AddViews(\n\t\tschema.NewMaterializedView(\"m2\", \"SELECT * FROM multi\").\n\t\t\tAddDeps(public.Views[0], m1, public.Tables[0]),\n\t)\n\tother.AddViews(\n\t\tschema.NewView(\"v4\", \"SELECT * FROM other.t2\").\n\t\t\tAddDeps(other.Tables[0]),\n\t)\n\tr.AddSchemas(public, other)\n\trequire.NoError(t, EvalHCLBytes([]byte(f), &got, nil))\n\trequire.EqualValues(t, r, got)\n}\n\nfunc TestUnmarshalSpec_IndexType(t *testing.T) {\n\tf := `\nschema \"s\" {}\ntable \"t\" {\n\tschema = schema.s\n\tcolumn \"c\" {\n\t\ttype = int\n\t}\n\tindex \"i\" {\n\t\ttype = %s\n\t\tcolumns = [column.c]\n\t}\n}\n`\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tf := fmt.Sprintf(f, \"UNK\")\n\t\terr := EvalHCLBytes([]byte(f), &schema.Schema{}, nil)\n\t\trequire.Error(t, err)\n\t})\n\tt.Run(\"Valid\", func(t *testing.T) {\n\t\tvar (\n\t\t\ts schema.Schema\n\t\t\tr = fmt.Sprintf(f, \"HASH\")\n\t\t)\n\t\trequire.NoError(t, EvalHCLBytes([]byte(r), &s, nil))\n\t\tidx := s.Tables[0].Indexes[0]\n\t\trequire.Equal(t, IndexTypeHash, idx.Attrs[0].(*IndexType).T)\n\n\t\ts = schema.Schema{}\n\t\tr = fmt.Sprintf(f, \"GiST\")\n\t\trequire.NoError(t, EvalHCLBytes([]byte(r), &s, nil))\n\t\tidx = s.Tables[0].Indexes[0]\n\t\trequire.Equal(t, IndexTypeGiST, idx.Attrs[0].(*IndexType).T)\n\n\t\ts = schema.Schema{}\n\t\tr = fmt.Sprintf(f, `\"HNSW\"`)\n\t\trequire.NoError(t, EvalHCLBytes([]byte(r), &s, nil))\n\t\tidx = s.Tables[0].Indexes[0]\n\t\trequire.Equal(t, \"HNSW\", idx.Attrs[0].(*IndexType).T)\n\t})\n}\n\nfunc TestMarshalSpec_IndexType(t *testing.T) {\n\ts := schema.New(\"public\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewIndex(\"i1\").AddAttrs(&IndexType{T: IndexTypeHash}),\n\t\t\t\t\tschema.NewIndex(\"i2\").AddAttrs(&IndexType{T: \"HNSW\"}),\n\t\t\t\t\tschema.NewIndex(\"i2\").AddAttrs(&IndexType{T: IndexTypeBTree}), // Default.\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `table \"t1\" {\n  schema = schema.public\n  column \"id\" {\n    null = false\n    type = int\n  }\n  index \"i1\" {\n    type = HASH\n  }\n  index \"i2\" {\n    type = \"HNSW\"\n  }\n  index \"i2\" {\n  }\n}\nschema \"public\" {\n}\n`,\n\t\tstring(buf))\n}\n\nfunc TestUnmarshalSpec_BRINIndex(t *testing.T) {\n\tf := `\nschema \"s\" {}\ntable \"t\" {\n\tschema = schema.s\n\tcolumn \"c\" {\n\t\ttype = int\n\t}\n\tindex \"i\" {\n\t\ttype = BRIN\n\t\tcolumns = [column.c]\n\t\tpage_per_range = 2\n\t}\n}\n`\n\tvar s schema.Schema\n\terr := EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\tidx := s.Tables[0].Indexes[0]\n\trequire.Equal(t, IndexTypeBRIN, idx.Attrs[0].(*IndexType).T)\n\trequire.EqualValues(t, 2, idx.Attrs[1].(*IndexStorageParams).PagesPerRange)\n}\n\nfunc TestUnmarshalSpec_IndexOpClass(t *testing.T) {\n\tconst f = `table \"users\" {\n  schema = schema.test\n  column \"a\" {\n    null = false\n    type = text\n  }\n  column \"b\" {\n    null = false\n    type = tsvector\n  }\n  index \"idx0\" {\n    unique  = true\n    columns = [column.a, column.b]\n  }\n  index \"idx1\" {\n    unique = true\n    on {\n      column = column.a\n      ops    = text_pattern_ops\n    }\n    on {\n      column = column.b\n    }\n  }\n  index \"idx2\" {\n    unique  = true\n    columns = [column.a]\n  }\n  index \"idx3\" {\n    unique = true\n    on {\n      column = column.a\n      ops    = text_pattern_ops\n    }\n  }\n  index \"idx4\" {\n    unique = true\n    type   = GIST\n    on {\n      column = column.b\n      ops    = sql(\"tsvector_ops(siglen=1)\")\n    }\n  }\n  index \"idx5\" {\n    unique = true\n    on {\n      column = column.a\n      ops    = \"vector_cosine_ops\"\n    }\n  }\n}\nschema \"test\" {\n}\n`\n\tvar s schema.Schema\n\terr := EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\t// idx0\n\tidx := s.Tables[0].Indexes[0]\n\trequire.Len(t, idx.Parts, 2)\n\trequire.Equal(t, \"a\", idx.Parts[0].C.Name)\n\trequire.Empty(t, idx.Parts[0].Attrs)\n\trequire.Equal(t, \"b\", idx.Parts[1].C.Name)\n\trequire.Empty(t, idx.Parts[1].Attrs)\n\t// idx1\n\tidx = s.Tables[0].Indexes[1]\n\trequire.Len(t, idx.Parts, 2)\n\trequire.Equal(t, \"a\", idx.Parts[0].C.Name)\n\trequire.Len(t, idx.Parts[0].Attrs, 1)\n\trequire.Equal(t, \"text_pattern_ops\", idx.Parts[0].Attrs[0].(*IndexOpClass).Name)\n\trequire.Equal(t, \"b\", idx.Parts[1].C.Name)\n\trequire.Empty(t, idx.Parts[1].Attrs)\n\t// idx2\n\tidx = s.Tables[0].Indexes[2]\n\trequire.Len(t, idx.Parts, 1)\n\trequire.Equal(t, \"a\", idx.Parts[0].C.Name)\n\trequire.Empty(t, idx.Parts[0].Attrs)\n\t// idx3\n\tidx = s.Tables[0].Indexes[3]\n\trequire.Len(t, idx.Parts, 1)\n\trequire.Equal(t, \"a\", idx.Parts[0].C.Name)\n\trequire.Len(t, idx.Parts[0].Attrs, 1)\n\trequire.Equal(t, \"text_pattern_ops\", idx.Parts[0].Attrs[0].(*IndexOpClass).Name)\n\t// idx4\n\tidx = s.Tables[0].Indexes[4]\n\trequire.Len(t, idx.Parts, 1)\n\trequire.Equal(t, \"b\", idx.Parts[0].C.Name)\n\trequire.Len(t, idx.Parts[0].Attrs, 1)\n\topc := idx.Parts[0].Attrs[0].(*IndexOpClass)\n\trequire.Equal(t, \"tsvector_ops\", opc.Name)\n\trequire.Len(t, opc.Params, 1)\n\trequire.Equal(t, \"siglen\", opc.Params[0].N)\n\trequire.Equal(t, \"1\", opc.Params[0].V)\n\t// idx5\n\tidx = s.Tables[0].Indexes[5]\n\trequire.Len(t, idx.Parts, 1)\n\trequire.Equal(t, \"a\", idx.Parts[0].C.Name)\n\trequire.Len(t, idx.Parts[0].Attrs, 1)\n\trequire.Equal(t, \"vector_cosine_ops\", idx.Parts[0].Attrs[0].(*IndexOpClass).Name)\n}\n\nfunc TestUnmarshalSpec_Partitioned(t *testing.T) {\n\tt.Run(\"Columns\", func(t *testing.T) {\n\t\tvar (\n\t\t\ts = &schema.Schema{}\n\t\t\tf = `\nschema \"test\" {}\ntable \"logs\" {\n\tschema = schema.test\n\tcolumn \"name\" {\n\t\ttype = text\n\t}\n\tpartition {\n\t\ttype = HASH\n\t\tcolumns = [\n\t\t\tcolumn.name\n\t\t]\n\t}\n}\n`\n\t\t)\n\t\terr := EvalHCLBytes([]byte(f), s, nil)\n\t\trequire.NoError(t, err)\n\t\tc := schema.NewStringColumn(\"name\", \"text\")\n\t\texpected := schema.New(\"test\").\n\t\t\tAddTables(schema.NewTable(\"logs\").AddColumns(c).AddAttrs(&Partition{T: PartitionTypeHash, Parts: []*PartitionPart{{C: c}}}))\n\t\texpected.SetRealm(schema.NewRealm(expected))\n\t\trequire.Equal(t, expected, s)\n\t})\n\n\tt.Run(\"Parts\", func(t *testing.T) {\n\t\tvar (\n\t\t\ts = &schema.Schema{}\n\t\t\tf = `\nschema \"test\" {}\ntable \"logs\" {\n\tschema = schema.test\n\tcolumn \"name\" {\n\t\ttype = text\n\t}\n\tpartition {\n\t\ttype = RANGE\n\t\tby {\n\t\t\tcolumn = column.name\n\t\t}\n\t\tby {\n\t\t\texpr = \"lower(name)\"\n\t\t}\n\t}\n}\n`\n\t\t)\n\t\terr := EvalHCLBytes([]byte(f), s, nil)\n\t\trequire.NoError(t, err)\n\t\tc := schema.NewStringColumn(\"name\", \"text\")\n\t\texpected := schema.New(\"test\").\n\t\t\tAddTables(schema.NewTable(\"logs\").AddColumns(c).AddAttrs(&Partition{T: PartitionTypeRange, Parts: []*PartitionPart{{C: c}, {X: &schema.RawExpr{X: \"lower(name)\"}}}}))\n\t\texpected.SetRealm(schema.NewRealm(expected))\n\t\trequire.Equal(t, expected, s)\n\t})\n\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\terr := EvalHCLBytes([]byte(`\n\t\t\tschema \"test\" {}\n\t\t\ttable \"logs\" {\n\t\t\t\tschema = schema.test\n\t\t\t\tcolumn \"name\" { type = text }\n\t\t\t\tpartition {\n\t\t\t\t\tcolumns = [column.name]\n\t\t\t\t}\n\t\t\t}\n\t\t`), &schema.Schema{}, nil)\n\t\trequire.Error(t, err, \"missing partition type\")\n\n\t\terr = EvalHCLBytes([]byte(`\n\t\t\tschema \"test\" {}\n\t\t\ttable \"logs\" {\n\t\t\t\tschema = schema.test\n\t\t\t\tcolumn \"name\" { type = text }\n\t\t\t\tpartition {\n\t\t\t\t\ttype = HASH\n\t\t\t\t}\n\t\t\t}\n\t\t`), &schema.Schema{}, nil)\n\t\trequire.EqualError(t, err, `cannot convert table \"logs\": missing columns or expressions for logs.partition`)\n\n\t\terr = EvalHCLBytes([]byte(`\n\t\t\tschema \"test\" {}\n\t\t\ttable \"logs\" {\n\t\t\t\tschema = schema.test\n\t\t\t\tcolumn \"name\" { type = text }\n\t\t\t\tpartition {\n\t\t\t\t\ttype = HASH\n\t\t\t\t\tcolumns = [column.name]\n\t\t\t\t\tby { column = column.name }\n\t\t\t\t}\n\t\t\t}\n\t\t`), &schema.Schema{}, nil)\n\t\trequire.EqualError(t, err, `cannot convert table \"logs\": multiple definitions for logs.partition, use \"columns\" or \"by\"`)\n\t})\n}\n\nfunc TestMarshalSpec_Partitioned(t *testing.T) {\n\tt.Run(\"Columns\", func(t *testing.T) {\n\t\tc := schema.NewStringColumn(\"name\", \"text\")\n\t\ts := schema.New(\"test\").\n\t\t\tAddTables(schema.NewTable(\"logs\").AddColumns(c).AddAttrs(&Partition{T: PartitionTypeHash, Parts: []*PartitionPart{{C: c}}}))\n\t\tbuf, err := MarshalHCL(s)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, `table \"logs\" {\n  schema = schema.test\n  column \"name\" {\n    null = false\n    type = text\n  }\n  partition {\n    type    = HASH\n    columns = [column.name]\n  }\n}\nschema \"test\" {\n}\n`, string(buf))\n\t})\n\n\tt.Run(\"Parts\", func(t *testing.T) {\n\t\tc := schema.NewStringColumn(\"name\", \"text\")\n\t\ts := schema.New(\"test\").\n\t\t\tAddTables(schema.NewTable(\"logs\").AddColumns(c).AddAttrs(&Partition{T: PartitionTypeHash, Parts: []*PartitionPart{{C: c}, {X: &schema.RawExpr{X: \"lower(name)\"}}}}))\n\t\tbuf, err := MarshalHCL(s)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, `table \"logs\" {\n  schema = schema.test\n  column \"name\" {\n    null = false\n    type = text\n  }\n  partition {\n    type = HASH\n    by {\n      column = column.name\n    }\n    by {\n      expr = \"lower(name)\"\n    }\n  }\n}\nschema \"test\" {\n}\n`, string(buf))\n\t})\n}\n\nfunc TestMarshalSpec_IndexPredicate(t *testing.T) {\n\ts := &schema.Schema{\n\t\tName: \"test\",\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"id\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\ts.Tables[0].Schema = s\n\ts.Tables[0].Schema = s\n\ts.Tables[0].Indexes = []*schema.Index{\n\t\t{\n\t\t\tName:   \"index\",\n\t\t\tTable:  s.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: s.Tables[0].Columns[0]},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexPredicate{P: \"id <> 0\"},\n\t\t\t},\n\t\t},\n\t}\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"id\" {\n    null = false\n    type = int\n  }\n  index \"index\" {\n    unique  = true\n    columns = [column.id]\n    where   = \"id <> 0\"\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_IndexNullsDistinct(t *testing.T) {\n\ts := schema.New(\"public\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"c\", \"int\"),\n\t\t\t\t).\n\t\t\t\tAddIndexes(\n\t\t\t\t\t// Default behavior.\n\t\t\t\t\tschema.NewUniqueIndex(\"without_attribute\").\n\t\t\t\t\t\tAddColumns(schema.NewColumn(\"c\")),\n\t\t\t\t\tschema.NewUniqueIndex(\"with_nulls_distinct\").\n\t\t\t\t\t\tAddColumns(schema.NewColumn(\"c\")).\n\t\t\t\t\t\tAddAttrs(&IndexNullsDistinct{V: true}),\n\t\t\t\t\t// Explicitly disable (NULLS NOT DISTINCT).\n\t\t\t\t\tschema.NewUniqueIndex(\"with_nulls_not_distinct\").\n\t\t\t\t\t\tAddColumns(schema.NewColumn(\"c\")).\n\t\t\t\t\t\tAddAttrs(&IndexNullsDistinct{V: false}),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.public\n  column \"c\" {\n    null = false\n    type = int\n  }\n  index \"without_attribute\" {\n    unique  = true\n    columns = [column.c]\n  }\n  index \"with_nulls_distinct\" {\n    unique  = true\n    columns = [column.c]\n  }\n  index \"with_nulls_not_distinct\" {\n    unique         = true\n    columns        = [column.c]\n    nulls_distinct = false\n  }\n}\nschema \"public\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_IndexNullsLastFirst(t *testing.T) {\n\ts := schema.New(\"public\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"c\", \"int\"),\n\t\t\t\t).\n\t\t\t\tAddIndexes(\n\t\t\t\t\t// Default behavior.\n\t\t\t\t\tschema.NewIndex(\"i1\").\n\t\t\t\t\t\tAddParts(schema.NewColumnPart(schema.NewColumn(\"c\")).SetDesc(true).AddAttrs(&IndexColumnProperty{NullsFirst: true})),\n\t\t\t\t\tschema.NewIndex(\"i2\").\n\t\t\t\t\t\tAddParts(schema.NewColumnPart(schema.NewColumn(\"c\")).SetDesc(false).AddAttrs(&IndexColumnProperty{NullsLast: true})),\n\t\t\t\t\t// Require emitting the NULLS FIRST/LAST attributes.\n\t\t\t\t\tschema.NewIndex(\"i3\").\n\t\t\t\t\t\tAddParts(schema.NewColumnPart(schema.NewColumn(\"c\")).SetDesc(true).AddAttrs(&IndexColumnProperty{NullsLast: true})),\n\t\t\t\t\tschema.NewIndex(\"i4\").\n\t\t\t\t\t\tAddParts(schema.NewColumnPart(schema.NewColumn(\"c\")).SetDesc(false).AddAttrs(&IndexColumnProperty{NullsFirst: true})),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.public\n  column \"c\" {\n    null = false\n    type = int\n  }\n  index \"i1\" {\n    on {\n      desc   = true\n      column = column.c\n    }\n  }\n  index \"i2\" {\n    columns = [column.c]\n  }\n  index \"i3\" {\n    on {\n      desc       = true\n      column     = column.c\n      nulls_last = true\n    }\n  }\n  index \"i4\" {\n    on {\n      column      = column.c\n      nulls_first = true\n    }\n  }\n}\nschema \"public\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n\n\tvar got schema.Schema\n\terr = EvalHCLBytes([]byte(expected), &got, nil)\n\trequire.NoError(t, err)\n\n\tbuf, err = MarshalHCL(s)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_BRINIndex(t *testing.T) {\n\ts := &schema.Schema{\n\t\tName: \"test\",\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"id\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\ts.Tables[0].Schema = s\n\ts.Tables[0].Schema = s\n\ts.Tables[0].Indexes = []*schema.Index{\n\t\t{\n\t\t\tName:   \"index\",\n\t\t\tTable:  s.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: s.Tables[0].Columns[0]},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexType{T: IndexTypeBRIN},\n\t\t\t\t&IndexStorageParams{PagesPerRange: 2},\n\t\t\t},\n\t\t},\n\t}\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"id\" {\n    null = false\n    type = int\n  }\n  index \"index\" {\n    unique         = true\n    columns        = [column.id]\n    type           = BRIN\n    page_per_range = 2\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_IndexOpClass(t *testing.T) {\n\ts := &schema.Schema{\n\t\tName: \"test\",\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"a\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"b\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &TextSearchType{T: \"tsvector\"}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\ts.Tables[0].Schema = s\n\ts.Tables[0].Schema = s\n\ts.Tables[0].Indexes = []*schema.Index{\n\t\t{\n\t\t\tName:   \"idx0\",\n\t\t\tTable:  s.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: s.Tables[0].Columns[0], Attrs: []schema.Attr{&IndexOpClass{Name: \"text_ops\"}}},\n\t\t\t\t{SeqNo: 1, C: s.Tables[0].Columns[1], Attrs: []schema.Attr{&IndexOpClass{Name: \"tsvector_ops\"}}},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexType{T: IndexTypeBTree},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:   \"idx1\",\n\t\t\tTable:  s.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: s.Tables[0].Columns[0], Attrs: []schema.Attr{&IndexOpClass{Name: \"text_pattern_ops\"}}},\n\t\t\t\t{SeqNo: 1, C: s.Tables[0].Columns[1], Attrs: []schema.Attr{&IndexOpClass{Name: \"tsvector_ops\"}}},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexType{T: IndexTypeBTree},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:   \"idx2\",\n\t\t\tTable:  s.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: s.Tables[0].Columns[0], Attrs: []schema.Attr{&IndexOpClass{Name: \"text_ops\"}}},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexType{T: IndexTypeBTree},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:   \"idx3\",\n\t\t\tTable:  s.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: s.Tables[0].Columns[0], Attrs: []schema.Attr{&IndexOpClass{Name: \"text_pattern_ops\"}}},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexType{T: IndexTypeBTree},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:   \"idx4\",\n\t\t\tTable:  s.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: s.Tables[0].Columns[1], Attrs: []schema.Attr{&IndexOpClass{Name: \"tsvector_ops\", Params: []struct{ N, V string }{{\"siglen\", \"1\"}}}}},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexType{T: IndexTypeGiST},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:   \"idx5\",\n\t\t\tTable:  s.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: s.Tables[0].Columns[0], Attrs: []schema.Attr{&IndexOpClass{Name: \"vector_cosine_ops\"}}},\n\t\t\t},\n\t\t},\n\t}\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"a\" {\n    null = false\n    type = text\n  }\n  column \"b\" {\n    null = false\n    type = tsvector\n  }\n  index \"idx0\" {\n    unique  = true\n    columns = [column.a, column.b]\n  }\n  index \"idx1\" {\n    unique = true\n    on {\n      column = column.a\n      ops    = text_pattern_ops\n    }\n    on {\n      column = column.b\n    }\n  }\n  index \"idx2\" {\n    unique  = true\n    columns = [column.a]\n  }\n  index \"idx3\" {\n    unique = true\n    on {\n      column = column.a\n      ops    = text_pattern_ops\n    }\n  }\n  index \"idx4\" {\n    unique = true\n    type   = GIST\n    on {\n      column = column.b\n      ops    = sql(\"tsvector_ops(siglen=1)\")\n    }\n  }\n  index \"idx5\" {\n    unique = true\n    on {\n      column = column.a\n      ops    = \"vector_cosine_ops\"\n    }\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestUnmarshalSpec_Identity(t *testing.T) {\n\tf := `\nschema \"s\" {}\ntable \"t\" {\n\tschema = schema.s\n\tcolumn \"c\" {\n\t\ttype = int\n\t\tidentity {\n\t\t\tgenerated = %s\n\t\t\tstart = 10\n\t\t}\n\t}\n}\n`\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tf := fmt.Sprintf(f, \"UNK\")\n\t\terr := EvalHCLBytes([]byte(f), &schema.Schema{}, nil)\n\t\trequire.Error(t, err)\n\t})\n\tt.Run(\"Valid\", func(t *testing.T) {\n\t\tvar (\n\t\t\ts schema.Schema\n\t\t\tf = fmt.Sprintf(f, \"ALWAYS\")\n\t\t)\n\t\terr := EvalHCLBytes([]byte(f), &s, nil)\n\t\trequire.NoError(t, err)\n\t\tid := s.Tables[0].Columns[0].Attrs[0].(*Identity)\n\t\trequire.Equal(t, GeneratedTypeAlways, id.Generation)\n\t\trequire.EqualValues(t, 10, id.Sequence.Start)\n\t\trequire.Zero(t, id.Sequence.Increment)\n\t})\n}\n\nfunc TestUnmarshalSpec_IndexInclude(t *testing.T) {\n\tf := `\nschema \"s\" {}\ntable \"t\" {\n\tschema = schema.s\n\tcolumn \"c\" {\n\t\ttype = int\n\t}\n\tcolumn \"d\" {\n\t\ttype = int\n\t}\n\tindex \"c\" {\n\t\tcolumns = [\n\t\t\tcolumn.c,\n\t\t]\n\t\tinclude = [\n\t\t\tcolumn.d,\n\t\t]\n\t}\n}\n`\n\tvar s schema.Schema\n\terr := EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\trequire.Len(t, s.Tables, 1)\n\trequire.Len(t, s.Tables[0].Columns, 2)\n\trequire.Len(t, s.Tables[0].Indexes, 1)\n\tidx, ok := s.Tables[0].Index(\"c\")\n\trequire.True(t, ok)\n\trequire.Len(t, idx.Parts, 1)\n\trequire.Len(t, idx.Attrs, 1)\n\tvar include IndexInclude\n\trequire.True(t, sqlx.Has(idx.Attrs, &include))\n\trequire.Len(t, include.Columns, 1)\n\trequire.Equal(t, \"d\", include.Columns[0].Name)\n}\n\nfunc TestMarshalSpec_IndexInclude(t *testing.T) {\n\ts := &schema.Schema{\n\t\tName: \"test\",\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"c\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"d\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\ts.Tables[0].Schema = s\n\ts.Tables[0].Indexes = []*schema.Index{\n\t\t{\n\t\t\tName:  \"index\",\n\t\t\tTable: s.Tables[0],\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: s.Tables[0].Columns[0]},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexInclude{Columns: s.Tables[0].Columns[1:]},\n\t\t\t},\n\t\t},\n\t}\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"c\" {\n    null = false\n    type = int\n  }\n  column \"d\" {\n    null = false\n    type = int\n  }\n  index \"index\" {\n    columns = [column.c]\n    include = [column.d]\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_PrimaryKey(t *testing.T) {\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"c\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"d\", \"int\"),\n\t\t\t\t),\n\t\t)\n\ts.Tables[0].SetPrimaryKey(\n\t\tschema.NewPrimaryKey(s.Tables[0].Columns[:1]...).\n\t\t\tAddAttrs(&IndexInclude{Columns: s.Tables[0].Columns[1:]}),\n\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"c\" {\n    null = false\n    type = int\n  }\n  column \"d\" {\n    null = false\n    type = int\n  }\n  primary_key {\n    columns = [column.c]\n    include = [column.d]\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestUnmarshalSpec_PrimaryKey(t *testing.T) {\n\tf := `\nschema \"s\" {}\ntable \"t\" {\n\tschema = schema.s\n\tcolumn \"c\" {\n\t\ttype = int\n\t}\n\tcolumn \"d\" {\n\t\ttype = int\n\t}\n\tprimary_key {\n\t\tcolumns = [\n\t\t\tcolumn.c,\n\t\t]\n\t\tinclude = [\n\t\t\tcolumn.d,\n\t\t]\n\t}\n}\n`\n\tvar s schema.Schema\n\terr := EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\trequire.Len(t, s.Tables, 1)\n\trequire.Len(t, s.Tables[0].Columns, 2)\n\tpk := s.Tables[0].PrimaryKey\n\trequire.NotNil(t, pk)\n\trequire.Len(t, pk.Parts, 1)\n\trequire.Len(t, pk.Attrs, 1)\n\tvar include IndexInclude\n\trequire.True(t, sqlx.Has(pk.Attrs, &include))\n\trequire.Len(t, include.Columns, 1)\n\trequire.Equal(t, \"d\", include.Columns[0].Name)\n}\n\nfunc TestMarshalSpec_GeneratedColumn(t *testing.T) {\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\").\n\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"c1 * 2\"}),\n\t\t\t\t\tschema.NewIntColumn(\"c2\", \"int\").\n\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"c3 * c4\", Type: \"STORED\"}),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"c1\" {\n    null = false\n    type = int\n    as {\n      expr = \"c1 * 2\"\n      type = STORED\n    }\n  }\n  column \"c2\" {\n    null = false\n    type = int\n    as {\n      expr = \"c3 * c4\"\n      type = STORED\n    }\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestUnmarshalSpec_GeneratedColumns(t *testing.T) {\n\tvar (\n\t\ts schema.Schema\n\t\tf = `\nschema \"test\" {}\ntable \"users\" {\n\tschema = schema.test\n\tcolumn \"c1\" {\n\t\ttype = int\n\t\tas = \"1\"\n\t}\n\tcolumn \"c2\" {\n\t\ttype = int\n\t\tas {\n\t\t\texpr = \"2\"\n\t\t}\n\t}\n\tcolumn \"c3\" {\n\t\ttype = int\n\t\tas {\n\t\t\texpr = \"3\"\n\t\t\ttype = STORED\n\t\t}\n\t}\n}\n`\n\t)\n\terr := EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\texpected := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\tschema.NewIntColumn(\"c2\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"2\", Type: \"STORED\"}),\n\t\t\t\t\tschema.NewIntColumn(\"c3\", \"int\").SetGeneratedExpr(&schema.GeneratedExpr{Expr: \"3\", Type: \"STORED\"}),\n\t\t\t\t),\n\t\t)\n\texpected.SetRealm(schema.NewRealm(expected))\n\trequire.EqualValues(t, expected, &s)\n}\n\nfunc TestMarshalSpec_Enum(t *testing.T) {\n\tstateE := &schema.EnumType{\n\t\tT:      \"state\",\n\t\tValues: []string{\"on\", \"off\"},\n\t}\n\ttypeE := &schema.EnumType{\n\t\tT:      \"account_type\",\n\t\tValues: []string{\"private\", \"business\"},\n\t}\n\ts := schema.New(\"test\").\n\t\tAddObjects(\n\t\t\ttypeE, stateE,\n\t\t).\n\t\tAddTables(\n\t\t\tschema.NewTable(\"account\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewEnumColumn(\"account_type\",\n\t\t\t\t\t\tschema.EnumName(\"account_type\"),\n\t\t\t\t\t\tschema.EnumValues(\"private\", \"business\"),\n\t\t\t\t\t),\n\t\t\t\t\tschema.NewColumn(\"account_states\").\n\t\t\t\t\t\tSetType(&ArrayType{\n\t\t\t\t\t\t\tT:    \"states[]\",\n\t\t\t\t\t\t\tType: stateE,\n\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\tschema.NewTable(\"table2\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewColumn(\"account_type\").\n\t\t\t\t\t\tSetType(typeE),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"account\" {\n  schema = schema.test\n  column \"account_type\" {\n    null = false\n    type = enum.account_type\n  }\n  column \"account_states\" {\n    null = false\n    type = sql(\"states[]\")\n  }\n}\ntable \"table2\" {\n  schema = schema.test\n  column \"account_type\" {\n    null = false\n    type = enum.account_type\n  }\n}\nenum \"account_type\" {\n  schema = schema.test\n  values = [\"private\", \"business\"]\n}\nenum \"state\" {\n  schema = schema.test\n  values = [\"on\", \"off\"]\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_TimePrecision(t *testing.T) {\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"times\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewTimeColumn(\"t_time_def\", TypeTime),\n\t\t\t\t\tschema.NewTimeColumn(\"t_time_with_time_zone\", TypeTimeTZ, schema.TimePrecision(2)),\n\t\t\t\t\tschema.NewTimeColumn(\"t_time_without_time_zone\", TypeTime, schema.TimePrecision(2)),\n\t\t\t\t\tschema.NewTimeColumn(\"t_timestamp\", TypeTimestamp, schema.TimePrecision(2)),\n\t\t\t\t\tschema.NewTimeColumn(\"t_timestamptz\", TypeTimestampTZ, schema.TimePrecision(2)),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"times\" {\n  schema = schema.test\n  column \"t_time_def\" {\n    null = false\n    type = time\n  }\n  column \"t_time_with_time_zone\" {\n    null = false\n    type = timetz(2)\n  }\n  column \"t_time_without_time_zone\" {\n    null = false\n    type = time(2)\n  }\n  column \"t_timestamp\" {\n    null = false\n    type = timestamp(2)\n  }\n  column \"t_timestamptz\" {\n    null = false\n    type = timestamptz(2)\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestTypes(t *testing.T) {\n\tp := func(i int) *int { return &i }\n\tfor _, tt := range []struct {\n\t\ttypeExpr string\n\t\texpected schema.Type\n\t}{\n\t\t{\n\t\t\ttypeExpr: \"bit(10)\",\n\t\t\texpected: &BitType{T: TypeBit, Len: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `hstore`,\n\t\t\texpected: &UserDefinedType{T: \"hstore\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bit_varying(10)\",\n\t\t\texpected: &BitType{T: TypeBitVar, Len: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"boolean\",\n\t\t\texpected: &schema.BoolType{T: TypeBoolean},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bool\",\n\t\t\texpected: &schema.BoolType{T: TypeBool},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bytea\",\n\t\t\texpected: &schema.BinaryType{T: TypeBytea},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"varchar(255)\",\n\t\t\texpected: &schema.StringType{T: TypeVarChar, Size: 255},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"char(255)\",\n\t\t\texpected: &schema.StringType{T: TypeChar, Size: 255},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"character(255)\",\n\t\t\texpected: &schema.StringType{T: TypeCharacter, Size: 255},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"text\",\n\t\t\texpected: &schema.StringType{T: TypeText},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bpchar\",\n\t\t\texpected: &schema.StringType{T: TypeBPChar},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"smallint\",\n\t\t\texpected: &schema.IntegerType{T: TypeSmallInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"integer\",\n\t\t\texpected: &schema.IntegerType{T: TypeInteger},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bigint\",\n\t\t\texpected: &schema.IntegerType{T: TypeBigInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int\",\n\t\t\texpected: &schema.IntegerType{T: TypeInt},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int2\",\n\t\t\texpected: &schema.IntegerType{T: TypeInt2},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int4\",\n\t\t\texpected: &schema.IntegerType{T: TypeInt4},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int8\",\n\t\t\texpected: &schema.IntegerType{T: TypeInt8},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"cidr\",\n\t\t\texpected: &NetworkType{T: TypeCIDR},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"inet\",\n\t\t\texpected: &NetworkType{T: TypeInet},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"macaddr\",\n\t\t\texpected: &NetworkType{T: TypeMACAddr},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"macaddr8\",\n\t\t\texpected: &NetworkType{T: TypeMACAddr8},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"circle\",\n\t\t\texpected: &schema.SpatialType{T: TypeCircle},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"line\",\n\t\t\texpected: &schema.SpatialType{T: TypeLine},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"lseg\",\n\t\t\texpected: &schema.SpatialType{T: TypeLseg},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"box\",\n\t\t\texpected: &schema.SpatialType{T: TypeBox},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"path\",\n\t\t\texpected: &schema.SpatialType{T: TypePath},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"point\",\n\t\t\texpected: &schema.SpatialType{T: TypePoint},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"date\",\n\t\t\texpected: &schema.TimeType{T: TypeDate},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"time\",\n\t\t\texpected: typeTime(TypeTime, 6),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"time(4)\",\n\t\t\texpected: typeTime(TypeTime, 4),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"timetz\",\n\t\t\texpected: typeTime(TypeTimeTZ, 6),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"timestamp\",\n\t\t\texpected: typeTime(TypeTimestamp, 6),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"timestamp(4)\",\n\t\t\texpected: typeTime(TypeTimestamp, 4),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"timestamptz\",\n\t\t\texpected: typeTime(TypeTimestampTZ, 6),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"timestamptz(4)\",\n\t\t\texpected: typeTime(TypeTimestampTZ, 4),\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"interval\",\n\t\t\texpected: &IntervalType{T: \"interval\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"interval(1)\",\n\t\t\texpected: &IntervalType{T: \"interval\", Precision: p(1)},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"second\",\n\t\t\texpected: &IntervalType{T: \"interval\", F: \"second\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"minute_to_second\",\n\t\t\texpected: &IntervalType{T: \"interval\", F: \"minute to second\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"minute_to_second(2)\",\n\t\t\texpected: &IntervalType{T: \"interval\", F: \"minute to second\", Precision: p(2)},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"real\",\n\t\t\texpected: &schema.FloatType{T: TypeReal, Precision: 24},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"float\",\n\t\t\texpected: &schema.FloatType{T: TypeFloat},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"float(1)\",\n\t\t\texpected: &schema.FloatType{T: TypeFloat, Precision: 1},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"float(25)\",\n\t\t\texpected: &schema.FloatType{T: TypeFloat, Precision: 25},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"float8\",\n\t\t\texpected: &schema.FloatType{T: TypeFloat8, Precision: 53},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"float4\",\n\t\t\texpected: &schema.FloatType{T: TypeFloat4, Precision: 24},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"numeric\",\n\t\t\texpected: &schema.DecimalType{T: TypeNumeric},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"numeric(10)\",\n\t\t\texpected: &schema.DecimalType{T: TypeNumeric, Precision: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"numeric(10, 2)\",\n\t\t\texpected: &schema.DecimalType{T: TypeNumeric, Precision: 10, Scale: 2},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"decimal\",\n\t\t\texpected: &schema.DecimalType{T: TypeDecimal},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"decimal(10)\",\n\t\t\texpected: &schema.DecimalType{T: TypeDecimal, Precision: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"decimal(10,2)\",\n\t\t\texpected: &schema.DecimalType{T: TypeDecimal, Precision: 10, Scale: 2},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"smallserial\",\n\t\t\texpected: &SerialType{T: TypeSmallSerial},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"serial\",\n\t\t\texpected: &SerialType{T: TypeSerial},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bigserial\",\n\t\t\texpected: &SerialType{T: TypeBigSerial},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"serial2\",\n\t\t\texpected: &SerialType{T: TypeSerial2},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"serial4\",\n\t\t\texpected: &SerialType{T: TypeSerial4},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"serial8\",\n\t\t\texpected: &SerialType{T: TypeSerial8},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"xml\",\n\t\t\texpected: &XMLType{T: TypeXML},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"json\",\n\t\t\texpected: &schema.JSONType{T: TypeJSON},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"jsonb\",\n\t\t\texpected: &schema.JSONType{T: TypeJSONB},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"uuid\",\n\t\t\texpected: &schema.UUIDType{T: TypeUUID},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"money\",\n\t\t\texpected: &CurrencyType{T: TypeMoney},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int4range\",\n\t\t\texpected: &RangeType{T: TypeInt4Range},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int4multirange\",\n\t\t\texpected: &RangeType{T: TypeInt4MultiRange},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int8range\",\n\t\t\texpected: &RangeType{T: TypeInt8Range},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int8multirange\",\n\t\t\texpected: &RangeType{T: TypeInt8MultiRange},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"numrange\",\n\t\t\texpected: &RangeType{T: TypeNumRange},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"nummultirange\",\n\t\t\texpected: &RangeType{T: TypeNumMultiRange},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tsrange\",\n\t\t\texpected: &RangeType{T: TypeTSRange},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tsmultirange\",\n\t\t\texpected: &RangeType{T: TypeTSMultiRange},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tstzrange\",\n\t\t\texpected: &RangeType{T: TypeTSTZRange},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tstzmultirange\",\n\t\t\texpected: &RangeType{T: TypeTSTZMultiRange},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"daterange\",\n\t\t\texpected: &RangeType{T: TypeDateRange},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"datemultirange\",\n\t\t\texpected: &RangeType{T: TypeDateMultiRange},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"int[]\")`,\n\t\t\texpected: &ArrayType{Type: &schema.IntegerType{T: \"int\"}, T: \"int[]\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"int[2]\")`,\n\t\t\texpected: &ArrayType{Type: &schema.IntegerType{T: \"int\"}, T: \"int[]\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"text[][]\")`,\n\t\t\texpected: &ArrayType{Type: &schema.StringType{T: \"text\"}, T: \"text[]\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"integer [3][3]\")`,\n\t\t\texpected: &ArrayType{Type: &schema.IntegerType{T: \"integer\"}, T: \"integer[]\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"integer  ARRAY[4]\")`,\n\t\t\texpected: &ArrayType{Type: &schema.IntegerType{T: \"integer\"}, T: \"integer[]\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"integer ARRAY\")`,\n\t\t\texpected: &ArrayType{Type: &schema.IntegerType{T: \"integer\"}, T: \"integer[]\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"character varying(255) [1][2]\")`,\n\t\t\texpected: &ArrayType{Type: &schema.StringType{T: \"character varying\", Size: 255}, T: \"character varying(255)[]\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"character varying ARRAY[2]\")`,\n\t\t\texpected: &ArrayType{Type: &schema.StringType{T: \"character varying\"}, T: \"character varying[]\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"varchar(2) [ 2 ] [  ]\")`,\n\t\t\texpected: &ArrayType{Type: &schema.StringType{T: \"varchar\", Size: 2}, T: \"varchar(2)[]\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"CaseSensitive\")`,\n\t\t\texpected: &UserDefinedType{T: \"CaseSensitive\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"oid\",\n\t\t\texpected: &OIDType{T: typeOID},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"regclass\",\n\t\t\texpected: &OIDType{T: typeRegClass},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"name\",\n\t\t\texpected: &schema.StringType{T: typeName},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"xid\",\n\t\t\texpected: &schema.IntegerType{T: TypeXID},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"xid8\",\n\t\t\texpected: &schema.IntegerType{T: TypeXID8},\n\t\t},\n\t} {\n\t\tt.Run(tt.typeExpr, func(t *testing.T) {\n\t\t\tvar test schema.Schema\n\t\t\tdoc := fmt.Sprintf(`table \"test\" {\n\tschema = schema.test\n\tcolumn \"test\" {\n\t\tnull = false\n\t\ttype = %s\n\t}\n}\nschema \"test\" {\n}\n`, tt.typeExpr)\n\t\t\terr := EvalHCLBytes([]byte(doc), &test, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tcolspec := test.Tables[0].Columns[0]\n\t\t\trequire.EqualValues(t, tt.expected, colspec.Type.Type)\n\t\t\tspec, err := MarshalHCL(&test)\n\t\t\trequire.NoError(t, err)\n\t\t\tvar after schema.Schema\n\t\t\terr = EvalHCLBytes(spec, &after, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.EqualValues(t, tt.expected, after.Tables[0].Columns[0].Type.Type)\n\t\t})\n\t}\n}\n\nfunc typeTime(t string, p int) schema.Type {\n\treturn &schema.TimeType{T: t, Precision: &p}\n}\n\nfunc TestParseType_Time(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\ttyp      string\n\t\texpected schema.Type\n\t}{\n\t\t{\n\t\t\ttyp:      \"timestamptz\",\n\t\t\texpected: typeTime(TypeTimestampTZ, 6),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timestamptz(0)\",\n\t\t\texpected: typeTime(TypeTimestampTZ, 0),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timestamptz(6)\",\n\t\t\texpected: typeTime(TypeTimestampTZ, 6),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timestamp with time zone\",\n\t\t\texpected: typeTime(TypeTimestampTZ, 6),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timestamp(1) with time zone\",\n\t\t\texpected: typeTime(TypeTimestampTZ, 1),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timestamp\",\n\t\t\texpected: typeTime(TypeTimestamp, 6),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timestamp(0)\",\n\t\t\texpected: typeTime(TypeTimestamp, 0),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timestamp(6)\",\n\t\t\texpected: typeTime(TypeTimestamp, 6),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timestamp without time zone\",\n\t\t\texpected: typeTime(TypeTimestamp, 6),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timestamp(1) without time zone\",\n\t\t\texpected: typeTime(TypeTimestamp, 1),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"time\",\n\t\t\texpected: typeTime(TypeTime, 6),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"time(3)\",\n\t\t\texpected: typeTime(TypeTime, 3),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"time without time zone\",\n\t\t\texpected: typeTime(TypeTime, 6),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"time(3) without time zone\",\n\t\t\texpected: typeTime(TypeTime, 3),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timetz\",\n\t\t\texpected: typeTime(TypeTimeTZ, 6),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"timetz(4)\",\n\t\t\texpected: typeTime(TypeTimeTZ, 4),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"time with time zone\",\n\t\t\texpected: typeTime(TypeTimeTZ, 6),\n\t\t},\n\t\t{\n\t\t\ttyp:      \"time(4) with time zone\",\n\t\t\texpected: typeTime(TypeTimeTZ, 4),\n\t\t},\n\t} {\n\t\tt.Run(tt.typ, func(t *testing.T) {\n\t\t\ttyp, err := ParseType(tt.typ)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.expected, typ)\n\t\t})\n\t}\n}\n\nfunc TestFormatType_Interval(t *testing.T) {\n\tp := func(i int) *int { return &i }\n\tfor i, tt := range []struct {\n\t\ttyp *IntervalType\n\t\tfmt string\n\t}{\n\t\t{\n\t\t\ttyp: &IntervalType{T: \"interval\"},\n\t\t\tfmt: \"interval\",\n\t\t},\n\t\t{\n\t\t\ttyp: &IntervalType{T: \"interval\", Precision: p(6)},\n\t\t\tfmt: \"interval\",\n\t\t},\n\t\t{\n\t\t\ttyp: &IntervalType{T: \"interval\", Precision: p(3)},\n\t\t\tfmt: \"interval(3)\",\n\t\t},\n\t\t{\n\t\t\ttyp: &IntervalType{T: \"interval\", F: \"DAY\"},\n\t\t\tfmt: \"interval day\",\n\t\t},\n\t\t{\n\t\t\ttyp: &IntervalType{T: \"interval\", F: \"HOUR TO SECOND\"},\n\t\t\tfmt: \"interval hour to second\",\n\t\t},\n\t\t{\n\t\t\ttyp: &IntervalType{T: \"interval\", F: \"HOUR TO SECOND\", Precision: p(2)},\n\t\t\tfmt: \"interval hour to second(2)\",\n\t\t},\n\t\t{\n\t\t\ttyp: &IntervalType{T: \"interval\", F: \"DAY TO HOUR\", Precision: p(6)},\n\t\t\tfmt: \"interval day to hour\",\n\t\t},\n\t} {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tf, err := FormatType(tt.typ)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.fmt, f)\n\t\t})\n\t}\n}\nfunc TestParseType_Interval(t *testing.T) {\n\tp := func(i int) *int { return &i }\n\tfor i, tt := range []struct {\n\t\ttyp    string\n\t\tparsed *IntervalType\n\t}{\n\t\t{\n\t\t\ttyp:    \"interval\",\n\t\t\tparsed: &IntervalType{T: \"interval\", Precision: p(6)},\n\t\t},\n\t\t{\n\t\t\ttyp:    \"interval(2)\",\n\t\t\tparsed: &IntervalType{T: \"interval\", Precision: p(2)},\n\t\t},\n\t\t{\n\t\t\ttyp:    \"interval day\",\n\t\t\tparsed: &IntervalType{T: \"interval\", F: \"day\", Precision: p(6)},\n\t\t},\n\t\t{\n\t\t\ttyp:    \"interval day to second(2)\",\n\t\t\tparsed: &IntervalType{T: \"interval\", F: \"day to second\", Precision: p(2)},\n\t\t},\n\t\t{\n\t\t\ttyp:    \"interval day to second (2)\",\n\t\t\tparsed: &IntervalType{T: \"interval\", F: \"day to second\", Precision: p(2)},\n\t\t},\n\t} {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tp, err := ParseType(tt.typ)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.parsed, p)\n\t\t})\n\t}\n}\n\nfunc TestRegistrySanity(t *testing.T) {\n\tspectest.RegistrySanityTest(t, TypeRegistry, []string{\"enum\"})\n}\n\nfunc TestInputVars(t *testing.T) {\n\tspectest.TestInputVars(t, EvalHCL)\n}\n\nfunc TestMarshalRealm(t *testing.T) {\n\tt1 := schema.NewTable(\"t1\").\n\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\"))\n\tt2 := schema.NewTable(\"t2\").\n\t\tSetComment(\"Qualified with s1\").\n\t\tAddColumns(schema.NewIntColumn(\"oid\", \"int\"))\n\tt2.AddForeignKeys(schema.NewForeignKey(\"oid2id\").AddColumns(t2.Columns[0]).SetRefTable(t1).AddRefColumns(t1.Columns[0]))\n\n\tt3 := schema.NewTable(\"t3\").\n\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\"))\n\tt4 := schema.NewTable(\"t2\").\n\t\tSetComment(\"Qualified with s2\").\n\t\tAddColumns(schema.NewIntColumn(\"oid\", \"int\"))\n\tt4.AddForeignKeys(schema.NewForeignKey(\"oid2id\").AddColumns(t4.Columns[0]).SetRefTable(t3).AddRefColumns(t3.Columns[0]))\n\tt5 := schema.NewTable(\"t5\").\n\t\tAddColumns(schema.NewIntColumn(\"oid\", \"int\"))\n\tt5.AddForeignKeys(schema.NewForeignKey(\"oid2id1\").AddColumns(t5.Columns[0]).SetRefTable(t1).AddRefColumns(t1.Columns[0]))\n\t// Reference is qualified with s1.\n\tt5.AddForeignKeys(schema.NewForeignKey(\"oid2id2\").AddColumns(t5.Columns[0]).SetRefTable(t2).AddRefColumns(t2.Columns[0]))\n\n\t// Two views with the same name resided in different schemas.\n\tv2 := schema.NewView(\"v2\", \"SELECT oid FROM s1.t2\").\n\t\tAddColumns(schema.NewIntColumn(\"oid\", \"int\")).\n\t\tAddDeps(t2)\n\tv4 := schema.NewView(\"v2\", \"SELECT oid FROM s2.t2\").\n\t\tAddColumns(schema.NewIntColumn(\"oid\", \"int\")).\n\t\tAddDeps(t4)\n\n\tr := schema.NewRealm(\n\t\tschema.New(\"s1\").AddTables(t1, t2).AddViews(v2),\n\t\tschema.New(\"s2\").AddTables(t3, t4, t5).AddViews(v4),\n\t)\n\tgot, err := MarshalHCL.MarshalSpec(r)\n\trequire.NoError(t, err)\n\trequire.Equal(\n\t\tt,\n\t\t`table \"t1\" {\n  schema = schema.s1\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\ntable \"s1\" \"t2\" {\n  schema  = schema.s1\n  comment = \"Qualified with s1\"\n  column \"oid\" {\n    null = false\n    type = int\n  }\n  foreign_key \"oid2id\" {\n    columns     = [column.oid]\n    ref_columns = [table.t1.column.id]\n  }\n}\ntable \"t3\" {\n  schema = schema.s2\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\ntable \"s2\" \"t2\" {\n  schema  = schema.s2\n  comment = \"Qualified with s2\"\n  column \"oid\" {\n    null = false\n    type = int\n  }\n  foreign_key \"oid2id\" {\n    columns     = [column.oid]\n    ref_columns = [table.t3.column.id]\n  }\n}\ntable \"t5\" {\n  schema = schema.s2\n  column \"oid\" {\n    null = false\n    type = int\n  }\n  foreign_key \"oid2id1\" {\n    columns     = [column.oid]\n    ref_columns = [table.t1.column.id]\n  }\n  foreign_key \"oid2id2\" {\n    columns     = [column.oid]\n    ref_columns = [table.s1.t2.column.oid]\n  }\n}\nview \"s1\" \"v2\" {\n  schema = schema.s1\n  column \"oid\" {\n    null = false\n    type = int\n  }\n  as         = \"SELECT oid FROM s1.t2\"\n  depends_on = [table.s1.t2]\n}\nview \"s2\" \"v2\" {\n  schema = schema.s2\n  column \"oid\" {\n    null = false\n    type = int\n  }\n  as         = \"SELECT oid FROM s2.t2\"\n  depends_on = [table.s2.t2]\n}\nschema \"s1\" {\n}\nschema \"s2\" {\n}\n`,\n\t\tstring(got))\n}\n\nfunc TestMarshalSkipQualifiers(t *testing.T) {\n\tbuf, err := MarshalHCL.MarshalSpec(\n\t\tschema.New(\"s1\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"id1\", \"int\")),\n\t\t\t\tschema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"id2\", \"int\")),\n\t\t\t),\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `table \"t1\" {\n  schema = schema.s1\n  column \"id1\" {\n    null = false\n    type = int\n  }\n}\ntable \"t1\" {\n  schema = schema.s1\n  column \"id2\" {\n    null = false\n    type = int\n  }\n}\nschema \"s1\" {\n}\n`, string(buf), \"qualifiers are skipped if objects belong to the same schema (repeatable blocks)\")\n}\n\nfunc TestMarshalQualifiers(t *testing.T) {\n\tvar (\n\t\ts1 = schema.New(\"s1\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t)\n\t\ts2 = schema.New(\"s2\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t).\n\t\t\tAddViews(\n\t\t\t\tschema.NewMaterializedView(\"m1\", \"SELECT id FROM s2.t1\"),\n\t\t\t)\n\t\ts3 = schema.New(\"s3\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"s1\").AddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t).\n\t\t\tAddViews(\n\t\t\t\tschema.NewMaterializedView(\"m1\", \"SELECT id FROM s3.t1\"),\n\t\t\t)\n\t)\n\ts2.Views[0].AddDeps(s2.Tables[0])\n\ts3.Views[0].AddDeps(s3.Tables[0])\n\tbuf, err := MarshalHCL.MarshalSpec(schema.NewRealm(s1, s2, s3))\n\trequire.NoError(t, err)\n\trequire.Equal(t, `table \"s1\" \"t1\" {\n  schema = schema.s1\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\ntable \"s2\" \"t1\" {\n  schema = schema.s2\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\ntable \"s3\" \"s1\" {\n  schema = schema.s3\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nmaterialized \"s2\" \"m1\" {\n  schema     = schema.s2\n  as         = \"SELECT id FROM s2.t1\"\n  depends_on = [table.s2.t1]\n}\nmaterialized \"s3\" \"m1\" {\n  schema     = schema.s3\n  as         = \"SELECT id FROM s3.t1\"\n  depends_on = [table.s1]\n}\nschema \"s1\" {\n}\nschema \"s2\" {\n}\nschema \"s3\" {\n}\n`, string(buf))\n}\n\nfunc TestMarshalSpec_UniqueConstraint(t *testing.T) {\n\ts := schema.New(\"public\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"uid\", \"int\"),\n\t\t\t\t).\n\t\t\t\tAddIndexes(\n\t\t\t\t\tschema.NewUniqueIndex(\"u1\").AddColumns(schema.NewColumn(\"id\")).AddAttrs(UniqueConstraint(\"u1\")),\n\t\t\t\t\tschema.NewUniqueIndex(\"u2\").AddColumns(schema.NewColumn(\"id\")).AddAttrs(UniqueConstraint(\"u2\"), &IndexNullsDistinct{}),\n\t\t\t\t\tschema.NewUniqueIndex(\"u3\").AddColumns(schema.NewColumn(\"id\")).AddAttrs(UniqueConstraint(\"u3\"), &IndexInclude{Columns: []*schema.Column{schema.NewColumn(\"uid\")}}),\n\t\t\t\t),\n\t\t)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `table \"t1\" {\n  schema = schema.public\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"uid\" {\n    null = false\n    type = int\n  }\n  unique \"u1\" {\n    columns = [column.id]\n  }\n  unique \"u2\" {\n    columns        = [column.id]\n    nulls_distinct = false\n  }\n  unique \"u3\" {\n    columns = [column.id]\n    include = [column.uid]\n  }\n}\nschema \"public\" {\n}\n`,\n\t\tstring(buf))\n}\n\nfunc TestUnmarshalSpec_UniqueConstraint(t *testing.T) {\n\tvar s schema.Schema\n\trequire.NoError(t, EvalHCLBytes([]byte(`table \"t1\" {\n  schema = schema.public\n  column \"id\" {\n    null = false\n    type = int\n  }\n  column \"uid\" {\n    null = false\n    type = int\n  }\n  unique \"u1\" {\n    columns = [column.id]\n  }\n  unique \"u2\" {\n    columns        = [column.id]\n    nulls_distinct = false\n  }\n  unique \"u3\" {\n    columns = [column.id]\n    include = [column.uid]\n  }\n}\nschema \"public\" {\n}\n`), &s, nil))\n\trequire.Len(t, s.Tables, 1)\n\trequire.Len(t, s.Tables[0].Indexes, 3)\n\t// u1\n\tu1 := s.Tables[0].Indexes[0]\n\trequire.Equal(t, \"u1\", u1.Name)\n\trequire.Equal(t, UniqueConstraint(\"u1\"), u1.Attrs[0].(*Constraint))\n\t// u2\n\tu2 := s.Tables[0].Indexes[1]\n\trequire.Equal(t, \"u2\", u2.Name)\n\trequire.Equal(t, &IndexNullsDistinct{}, u2.Attrs[0])\n\trequire.Equal(t, UniqueConstraint(\"u2\"), u2.Attrs[1].(*Constraint))\n\t// u3\n\tu3 := s.Tables[0].Indexes[2]\n\trequire.Equal(t, \"u3\", u3.Name)\n\trequire.Equal(t, &IndexInclude{Columns: []*schema.Column{s.Tables[0].Columns[1]}}, u3.Attrs[0])\n\trequire.Equal(t, UniqueConstraint(\"u3\"), u3.Attrs[1].(*Constraint))\n}\n"
  },
  {
    "path": "sql/schema/changekind_string.go",
    "content": "// Code generated by \"stringer -type ChangeKind\"; DO NOT EDIT.\n\npackage schema\n\nimport \"strconv\"\n\nfunc _() {\n\t// An \"invalid array index\" compiler error signifies that the constant values have changed.\n\t// Re-run the stringer command to generate them again.\n\tvar x [1]struct{}\n\t_ = x[NoChange-0]\n\t_ = x[ChangeAttr-1]\n\t_ = x[ChangeCharset-2]\n\t_ = x[ChangeCollate-4]\n\t_ = x[ChangeComment-8]\n\t_ = x[ChangeNull-16]\n\t_ = x[ChangeType-32]\n\t_ = x[ChangeDefault-64]\n\t_ = x[ChangeGenerated-128]\n\t_ = x[ChangeUnique-256]\n\t_ = x[ChangeParts-512]\n\t_ = x[ChangeColumn-1024]\n\t_ = x[ChangeRefColumn-2048]\n\t_ = x[ChangeRefTable-4096]\n\t_ = x[ChangeUpdateAction-8192]\n\t_ = x[ChangeDeleteAction-16384]\n}\n\nconst _ChangeKind_name = \"NoChangeChangeAttrChangeCharsetChangeCollateChangeCommentChangeNullChangeTypeChangeDefaultChangeGeneratedChangeUniqueChangePartsChangeColumnChangeRefColumnChangeRefTableChangeUpdateActionChangeDeleteAction\"\n\nvar _ChangeKind_map = map[ChangeKind]string{\n\t0:     _ChangeKind_name[0:8],\n\t1:     _ChangeKind_name[8:18],\n\t2:     _ChangeKind_name[18:31],\n\t4:     _ChangeKind_name[31:44],\n\t8:     _ChangeKind_name[44:57],\n\t16:    _ChangeKind_name[57:67],\n\t32:    _ChangeKind_name[67:77],\n\t64:    _ChangeKind_name[77:90],\n\t128:   _ChangeKind_name[90:105],\n\t256:   _ChangeKind_name[105:117],\n\t512:   _ChangeKind_name[117:128],\n\t1024:  _ChangeKind_name[128:140],\n\t2048:  _ChangeKind_name[140:155],\n\t4096:  _ChangeKind_name[155:169],\n\t8192:  _ChangeKind_name[169:187],\n\t16384: _ChangeKind_name[187:205],\n}\n\nfunc (i ChangeKind) String() string {\n\tif str, ok := _ChangeKind_map[i]; ok {\n\t\treturn str\n\t}\n\treturn \"ChangeKind(\" + strconv.FormatInt(int64(i), 10) + \")\"\n}\n"
  },
  {
    "path": "sql/schema/dsl.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schema\n\nimport (\n\t\"reflect\"\n\t\"slices\"\n\t\"strings\"\n)\n\n// The functions and methods below provide a DSL for creating schema resources using\n// a fluent interface. Note that some methods create links between the schema elements.\n\n// New creates a new Schema.\nfunc New(name string) *Schema {\n\treturn &Schema{Name: name}\n}\n\n// SetCharset sets or appends the Charset attribute\n// to the schema with the given value.\nfunc (s *Schema) SetCharset(v string) *Schema {\n\tReplaceOrAppend(&s.Attrs, &Charset{V: v})\n\treturn s\n}\n\n// UnsetCharset unsets the Charset attribute.\nfunc (s *Schema) UnsetCharset() *Schema {\n\tdel(&s.Attrs, &Charset{})\n\treturn s\n}\n\n// SetCollation sets or appends the Collation attribute\n// to the schema with the given value.\nfunc (s *Schema) SetCollation(v string) *Schema {\n\tReplaceOrAppend(&s.Attrs, &Collation{V: v})\n\treturn s\n}\n\n// UnsetCollation the Collation attribute.\nfunc (s *Schema) UnsetCollation() *Schema {\n\tdel(&s.Attrs, &Collation{})\n\treturn s\n}\n\n// SetComment sets or appends the Comment attribute\n// to the schema with the given value.\nfunc (s *Schema) SetComment(v string) *Schema {\n\tReplaceOrAppend(&s.Attrs, &Comment{Text: v})\n\treturn s\n}\n\n// AddAttrs adds additional attributes to the schema.\nfunc (s *Schema) AddAttrs(attrs ...Attr) *Schema {\n\ts.Attrs = append(s.Attrs, attrs...)\n\treturn s\n}\n\n// SetRealm sets the database/realm of the schema.\nfunc (s *Schema) SetRealm(r *Realm) *Schema {\n\ts.Realm = r\n\treturn s\n}\n\n// AddTables adds and links the given tables to the schema.\nfunc (s *Schema) AddTables(tables ...*Table) *Schema {\n\tfor _, t := range tables {\n\t\tt.SetSchema(s)\n\t}\n\ts.Tables = append(s.Tables, tables...)\n\treturn s\n}\n\n// AddViews adds and links the given views to the schema.\nfunc (s *Schema) AddViews(views ...*View) *Schema {\n\tfor _, v := range views {\n\t\tv.SetSchema(s)\n\t}\n\ts.Views = append(s.Views, views...)\n\treturn s\n}\n\n// AddObjects adds the given objects to the schema.\nfunc (s *Schema) AddObjects(objs ...Object) *Schema {\n\ts.Objects = append(s.Objects, objs...)\n\treturn s\n}\n\n// AddFuncs appends the given functions to the schema.\nfunc (s *Schema) AddFuncs(funcs ...*Func) *Schema {\n\tfor _, f := range funcs {\n\t\tf.Schema = s\n\t}\n\ts.Funcs = append(s.Funcs, funcs...)\n\treturn s\n}\n\n// AddProcs appends the given procedures to the schema.\nfunc (s *Schema) AddProcs(procs ...*Proc) *Schema {\n\tfor _, f := range procs {\n\t\tf.Schema = s\n\t}\n\ts.Procs = append(s.Procs, procs...)\n\treturn s\n}\n\n// NewRealm creates a new Realm.\nfunc NewRealm(schemas ...*Schema) *Realm {\n\tr := &Realm{Schemas: schemas}\n\tfor _, s := range schemas {\n\t\ts.Realm = r\n\t}\n\treturn r\n}\n\n// AddSchemas adds and links the given schemas to the realm.\nfunc (r *Realm) AddSchemas(schemas ...*Schema) *Realm {\n\tfor _, s := range schemas {\n\t\ts.SetRealm(r)\n\t}\n\tr.Schemas = append(r.Schemas, schemas...)\n\treturn r\n}\n\n// AddObjects adds the given objects to the realm.\nfunc (r *Realm) AddObjects(objs ...Object) *Realm {\n\tr.Objects = append(r.Objects, objs...)\n\treturn r\n}\n\n// SetCharset sets or appends the Charset attribute\n// to the realm with the given value.\nfunc (r *Realm) SetCharset(v string) *Realm {\n\tReplaceOrAppend(&r.Attrs, &Charset{V: v})\n\treturn r\n}\n\n// UnsetCharset unsets the Charset attribute.\nfunc (r *Realm) UnsetCharset() *Realm {\n\tdel(&r.Attrs, &Charset{})\n\treturn r\n}\n\n// SetCollation sets or appends the Collation attribute\n// to the realm with the given value.\nfunc (r *Realm) SetCollation(v string) *Realm {\n\tReplaceOrAppend(&r.Attrs, &Collation{V: v})\n\treturn r\n}\n\n// UnsetCollation the Collation attribute.\nfunc (r *Realm) UnsetCollation() *Realm {\n\tdel(&r.Attrs, &Collation{})\n\treturn r\n}\n\n// NewTable creates a new Table.\nfunc NewTable(name string) *Table {\n\treturn &Table{Name: name}\n}\n\n// SetCharset sets or appends the Charset attribute\n// to the table with the given value.\nfunc (t *Table) SetCharset(v string) *Table {\n\tReplaceOrAppend(&t.Attrs, &Charset{V: v})\n\treturn t\n}\n\n// UnsetCharset unsets the Charset attribute.\nfunc (t *Table) UnsetCharset() *Table {\n\tdel(&t.Attrs, &Charset{})\n\treturn t\n}\n\n// SetCollation sets or appends the Collation attribute\n// to the table with the given value.\nfunc (t *Table) SetCollation(v string) *Table {\n\tReplaceOrAppend(&t.Attrs, &Collation{V: v})\n\treturn t\n}\n\n// UnsetCollation the Collation attribute.\nfunc (t *Table) UnsetCollation() *Table {\n\tdel(&t.Attrs, &Collation{})\n\treturn t\n}\n\n// SetComment sets or appends the Comment attribute\n// to the table with the given value.\nfunc (t *Table) SetComment(v string) *Table {\n\tReplaceOrAppend(&t.Attrs, &Comment{Text: v})\n\treturn t\n}\n\n// AddChecks appends the given checks to the attribute list.\nfunc (t *Table) AddChecks(checks ...*Check) *Table {\n\tfor _, c := range checks {\n\t\tt.Attrs = append(t.Attrs, c)\n\t}\n\treturn t\n}\n\n// SetSchema sets the schema (named-database) of the table.\nfunc (t *Table) SetSchema(s *Schema) *Table {\n\tt.Schema = s\n\treturn t\n}\n\n// SetPrimaryKey sets the primary-key of the table.\nfunc (t *Table) SetPrimaryKey(pk *Index) *Table {\n\tpk.Table = t\n\tt.PrimaryKey = pk\n\tfor _, p := range pk.Parts {\n\t\tif p.C == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif _, ok := t.Column(p.C.Name); !ok {\n\t\t\tt.AddColumns(p.C)\n\t\t}\n\t}\n\treturn t\n}\n\n// AddColumns appends the given columns to the table column list.\nfunc (t *Table) AddColumns(columns ...*Column) *Table {\n\tt.Columns = append(t.Columns, columns...)\n\treturn t\n}\n\n// AddIndexes appends the given indexes to the table index list.\nfunc (t *Table) AddIndexes(indexes ...*Index) *Table {\n\tfor _, idx := range indexes {\n\t\tidx.Table = t\n\t}\n\tt.Indexes = append(t.Indexes, indexes...)\n\treturn t\n}\n\n// AddForeignKeys appends the given foreign-keys to the table foreign-key list.\nfunc (t *Table) AddForeignKeys(fks ...*ForeignKey) *Table {\n\tfor _, fk := range fks {\n\t\tfk.Table = t\n\t}\n\tt.ForeignKeys = append(t.ForeignKeys, fks...)\n\treturn t\n}\n\n// AddAttrs adds and additional attributes to the table.\nfunc (t *Table) AddAttrs(attrs ...Attr) *Table {\n\tt.Attrs = append(t.Attrs, attrs...)\n\treturn t\n}\n\n// AddDeps adds the given objects as dependencies to the view.\nfunc (t *Table) AddDeps(objs ...Object) *Table {\n\tt.Deps = append(t.Deps, objs...)\n\taddRefs(t, objs)\n\treturn t\n}\n\n// RefsAdder wraps the AddRefs method. Objects that implemented this method\n// will get their dependent objects automatically set by their AddDeps calls.\ntype RefsAdder interface {\n\tAddRefs(...Object)\n}\n\n// addRefs adds the dependent objects to all objects it references.\nfunc addRefs(dependent Object, refs []Object) {\n\tfor _, o := range refs {\n\t\tif r, ok := o.(RefsAdder); ok {\n\t\t\tr.AddRefs(dependent)\n\t\t}\n\t}\n}\n\n// DepRemover wraps the RemoveDep method. Objects that implemented this method\n// allow dependent objects to remove themselves from their references.\ntype DepRemover interface {\n\tRemoveDep(Object)\n}\n\n// removeObj removes the given object from the list of objects.\nfunc removeObj(objs []Object, o Object) []Object {\n\ti := slices.Index(objs, o)\n\tif i == -1 {\n\t\treturn objs\n\t}\n\treturn append(objs[:i:i], objs[i+1:]...)\n}\n\n// SortRefs maintains consistent dependents list.\nfunc SortRefs(refs []Object) {\n\tslices.SortFunc(refs, func(a, b Object) int {\n\t\ttypeA, typeB := reflect.TypeOf(a), reflect.TypeOf(b)\n\t\tif typeA != typeB {\n\t\t\treturn strings.Compare(typeA.String(), typeB.String())\n\t\t}\n\t\tswitch o1 := a.(type) {\n\t\tcase *Table:\n\t\t\treturn strings.Compare(o1.Name, b.(*Table).Name)\n\t\tcase *View:\n\t\t\treturn strings.Compare(o1.Name, b.(*View).Name)\n\t\tcase *Trigger:\n\t\t\treturn strings.Compare(o1.Name, b.(*Trigger).Name)\n\t\tcase *Func:\n\t\t\treturn strings.Compare(o1.Name, b.(*Func).Name)\n\t\tcase *Proc:\n\t\t\treturn strings.Compare(o1.Name, b.(*Proc).Name)\n\t\tdefault:\n\t\t\treturn 0\n\t\t}\n\t})\n}\n\n// AddRefs adds references to the table.\nfunc (t *Table) AddRefs(refs ...Object) {\n\tt.Refs = append(t.Refs, refs...)\n\tSortRefs(t.Refs)\n}\n\n// RemoveDep removes the given object from the table dependencies.\nfunc (t *Table) RemoveDep(o Object) {\n\tt.Deps = removeObj(t.Deps, o)\n}\n\n// NewView creates a new View.\nfunc NewView(name, def string) *View {\n\treturn &View{Name: name, Def: def}\n}\n\n// NewMaterializedView creates a new materialized View.\nfunc NewMaterializedView(name, def string) *View {\n\treturn NewView(name, def).\n\t\tSetMaterialized(true)\n}\n\n// SetSchema sets the schema (named-database) of the view.\nfunc (v *View) SetSchema(s *Schema) *View {\n\tv.Schema = s\n\treturn v\n}\n\n// AddColumns appends the given columns to the table column list.\nfunc (v *View) AddColumns(columns ...*Column) *View {\n\tv.Columns = append(v.Columns, columns...)\n\treturn v\n}\n\n// SetComment sets or appends the Comment attribute\n// to the view with the given value.\nfunc (v *View) SetComment(c string) *View {\n\tReplaceOrAppend(&v.Attrs, &Comment{Text: c})\n\treturn v\n}\n\n// AddAttrs adds and additional attributes to the view.\nfunc (v *View) AddAttrs(attrs ...Attr) *View {\n\tv.Attrs = append(v.Attrs, attrs...)\n\treturn v\n}\n\n// AddDeps adds the given objects as dependencies to the view.\nfunc (v *View) AddDeps(objs ...Object) *View {\n\tv.Deps = append(v.Deps, objs...)\n\taddRefs(v, objs)\n\treturn v\n}\n\n// RemoveDep removes the given object from the view dependencies.\nfunc (v *View) RemoveDep(o Object) {\n\tv.Deps = removeObj(v.Deps, o)\n}\n\n// AddRefs adds references to the view.\nfunc (v *View) AddRefs(refs ...Object) {\n\tv.Refs = append(v.Refs, refs...)\n\tSortRefs(v.Refs)\n}\n\n// AddIndexes appends the given indexes to the table index list.\nfunc (v *View) AddIndexes(indexes ...*Index) *View {\n\tfor _, idx := range indexes {\n\t\tidx.View = v\n\t}\n\tv.Indexes = append(v.Indexes, indexes...)\n\treturn v\n}\n\n// SetCheckOption sets the check option of the view.\nfunc (v *View) SetCheckOption(opt string) *View {\n\tReplaceOrAppend(&v.Attrs, &ViewCheckOption{V: opt})\n\treturn v\n}\n\n// NewColumn creates a new column with the given name.\nfunc NewColumn(name string) *Column {\n\treturn &Column{Name: name}\n}\n\n// NewNullColumn creates a new nullable column with the given name.\nfunc NewNullColumn(name string) *Column {\n\treturn NewColumn(name).\n\t\tSetNull(true)\n}\n\n// NewBoolColumn creates a new BoolType column.\nfunc NewBoolColumn(name, typ string) *Column {\n\treturn NewColumn(name).\n\t\tSetType(&BoolType{T: typ})\n}\n\n// NewNullBoolColumn creates a new nullable BoolType column.\nfunc NewNullBoolColumn(name, typ string) *Column {\n\treturn NewBoolColumn(name, typ).\n\t\tSetNull(true)\n}\n\n// NewIntColumn creates a new IntegerType column.\nfunc NewIntColumn(name, typ string) *Column {\n\treturn NewColumn(name).\n\t\tSetType(&IntegerType{T: typ})\n}\n\n// NewNullIntColumn creates a new nullable IntegerType column.\nfunc NewNullIntColumn(name, typ string) *Column {\n\treturn NewIntColumn(name, typ).\n\t\tSetNull(true)\n}\n\n// NewUintColumn creates a new unsigned IntegerType column.\nfunc NewUintColumn(name, typ string) *Column {\n\treturn NewColumn(name).\n\t\tSetType(&IntegerType{T: typ, Unsigned: true})\n}\n\n// NewNullUintColumn creates a new nullable unsigned IntegerType column.\nfunc NewNullUintColumn(name, typ string) *Column {\n\treturn NewUintColumn(name, typ).\n\t\tSetNull(true)\n}\n\n// EnumOption allows configuring EnumType using functional options.\ntype EnumOption func(*EnumType)\n\n// EnumName configures the name of the name. This option\n// is useful for databases like PostgreSQL that supports\n// user-defined types for enums.\nfunc EnumName(name string) EnumOption {\n\treturn func(e *EnumType) {\n\t\te.T = name\n\t}\n}\n\n// EnumValues configures the values of the enum.\nfunc EnumValues(values ...string) EnumOption {\n\treturn func(e *EnumType) {\n\t\te.Values = values\n\t}\n}\n\n// EnumSchema configures the schema of the enum.\nfunc EnumSchema(s *Schema) EnumOption {\n\treturn func(e *EnumType) {\n\t\te.Schema = s\n\t}\n}\n\n// NewEnumColumn creates a new EnumType column.\nfunc NewEnumColumn(name string, opts ...EnumOption) *Column {\n\tt := &EnumType{}\n\tfor _, opt := range opts {\n\t\topt(t)\n\t}\n\treturn NewColumn(name).SetType(t)\n}\n\n// NewNullEnumColumn creates a new nullable EnumType column.\nfunc NewNullEnumColumn(name string, opts ...EnumOption) *Column {\n\treturn NewEnumColumn(name, opts...).\n\t\tSetNull(true)\n}\n\n// BinaryOption allows configuring BinaryType using functional options.\ntype BinaryOption func(*BinaryType)\n\n// BinarySize configures the size of the binary type.\nfunc BinarySize(size int) BinaryOption {\n\treturn func(b *BinaryType) {\n\t\tb.Size = &size\n\t}\n}\n\n// NewBinaryColumn creates a new BinaryType column.\nfunc NewBinaryColumn(name, typ string, opts ...BinaryOption) *Column {\n\tt := &BinaryType{T: typ}\n\tfor _, opt := range opts {\n\t\topt(t)\n\t}\n\treturn NewColumn(name).SetType(t)\n}\n\n// NewNullBinaryColumn creates a new nullable BinaryType column.\nfunc NewNullBinaryColumn(name, typ string, opts ...BinaryOption) *Column {\n\treturn NewBinaryColumn(name, typ, opts...).\n\t\tSetNull(true)\n}\n\n// StringOption allows configuring StringType using functional options.\ntype StringOption func(*StringType)\n\n// StringSize configures the size of the string type.\nfunc StringSize(size int) StringOption {\n\treturn func(b *StringType) {\n\t\tb.Size = size\n\t}\n}\n\n// NewStringColumn creates a new StringType column.\nfunc NewStringColumn(name, typ string, opts ...StringOption) *Column {\n\tt := &StringType{T: typ}\n\tfor _, opt := range opts {\n\t\topt(t)\n\t}\n\treturn NewColumn(name).SetType(t)\n}\n\n// NewNullStringColumn creates a new nullable StringType column.\nfunc NewNullStringColumn(name, typ string, opts ...StringOption) *Column {\n\treturn NewStringColumn(name, typ, opts...).\n\t\tSetNull(true)\n}\n\n// DecimalOption allows configuring DecimalType using functional options.\ntype DecimalOption func(*DecimalType)\n\n// DecimalPrecision configures the precision of the decimal type.\nfunc DecimalPrecision(precision int) DecimalOption {\n\treturn func(b *DecimalType) {\n\t\tb.Precision = precision\n\t}\n}\n\n// DecimalScale configures the scale of the decimal type.\nfunc DecimalScale(scale int) DecimalOption {\n\treturn func(b *DecimalType) {\n\t\tb.Scale = scale\n\t}\n}\n\n// DecimalUnsigned configures the unsigned of the float type.\nfunc DecimalUnsigned(unsigned bool) DecimalOption {\n\treturn func(b *DecimalType) {\n\t\tb.Unsigned = unsigned\n\t}\n}\n\n// NewDecimalColumn creates a new DecimalType column.\nfunc NewDecimalColumn(name, typ string, opts ...DecimalOption) *Column {\n\tt := &DecimalType{T: typ}\n\tfor _, opt := range opts {\n\t\topt(t)\n\t}\n\treturn NewColumn(name).SetType(t)\n}\n\n// NewNullDecimalColumn creates a new nullable DecimalType column.\nfunc NewNullDecimalColumn(name, typ string, opts ...DecimalOption) *Column {\n\treturn NewDecimalColumn(name, typ, opts...).\n\t\tSetNull(true)\n}\n\n// FloatOption allows configuring FloatType using functional options.\ntype FloatOption func(*FloatType)\n\n// FloatPrecision configures the precision of the float type.\nfunc FloatPrecision(precision int) FloatOption {\n\treturn func(b *FloatType) {\n\t\tb.Precision = precision\n\t}\n}\n\n// FloatUnsigned configures the unsigned of the float type.\nfunc FloatUnsigned(unsigned bool) FloatOption {\n\treturn func(b *FloatType) {\n\t\tb.Unsigned = unsigned\n\t}\n}\n\n// NewFloatColumn creates a new FloatType column.\nfunc NewFloatColumn(name, typ string, opts ...FloatOption) *Column {\n\tt := &FloatType{T: typ}\n\tfor _, opt := range opts {\n\t\topt(t)\n\t}\n\treturn NewColumn(name).SetType(t)\n}\n\n// NewNullFloatColumn creates a new nullable FloatType column.\nfunc NewNullFloatColumn(name, typ string, opts ...FloatOption) *Column {\n\treturn NewFloatColumn(name, typ, opts...).\n\t\tSetNull(true)\n}\n\n// TimeOption allows configuring TimeType using functional options.\ntype TimeOption func(*TimeType)\n\n// TimePrecision configures the precision of the time type.\nfunc TimePrecision(precision int) TimeOption {\n\treturn func(b *TimeType) {\n\t\tb.Precision = &precision\n\t}\n}\n\n// TimeScale configures the scale of the time type.\nfunc TimeScale(scale int) TimeOption {\n\treturn func(b *TimeType) {\n\t\tb.Scale = &scale\n\t}\n}\n\n// NewTimeColumn creates a new TimeType column.\nfunc NewTimeColumn(name, typ string, opts ...TimeOption) *Column {\n\tt := &TimeType{T: typ}\n\tfor _, opt := range opts {\n\t\topt(t)\n\t}\n\treturn NewColumn(name).SetType(t)\n}\n\n// NewNullTimeColumn creates a new nullable TimeType column.\nfunc NewNullTimeColumn(name, typ string) *Column {\n\treturn NewTimeColumn(name, typ).\n\t\tSetNull(true)\n}\n\n// NewJSONColumn creates a new JSONType column.\nfunc NewJSONColumn(name, typ string) *Column {\n\treturn NewColumn(name).\n\t\tSetType(&JSONType{T: typ})\n}\n\n// NewNullJSONColumn creates a new nullable JSONType column.\nfunc NewNullJSONColumn(name, typ string) *Column {\n\treturn NewJSONColumn(name, typ).\n\t\tSetNull(true)\n}\n\n// NewSpatialColumn creates a new SpatialType column.\nfunc NewSpatialColumn(name, typ string) *Column {\n\treturn NewColumn(name).\n\t\tSetType(&SpatialType{T: typ})\n}\n\n// NewNullSpatialColumn creates a new nullable SpatialType column.\nfunc NewNullSpatialColumn(name, typ string) *Column {\n\treturn NewSpatialColumn(name, typ).\n\t\tSetNull(true)\n}\n\n// SetNull configures the nullability of the column\nfunc (c *Column) SetNull(b bool) *Column {\n\tif c.Type == nil {\n\t\tc.Type = &ColumnType{}\n\t}\n\tc.Type.Null = b\n\treturn c\n}\n\n// SetType configures the type of the column\nfunc (c *Column) SetType(t Type) *Column {\n\tif c.Type == nil {\n\t\tc.Type = &ColumnType{}\n\t}\n\tc.Type.Type = t\n\treturn c\n}\n\n// SetDefault configures the default of the column\nfunc (c *Column) SetDefault(x Expr) *Column {\n\tc.Default = x\n\treturn c\n}\n\n// SetCharset sets or appends the Charset attribute\n// to the column with the given value.\nfunc (c *Column) SetCharset(v string) *Column {\n\tReplaceOrAppend(&c.Attrs, &Charset{V: v})\n\treturn c\n}\n\n// UnsetCharset unsets the Charset attribute.\nfunc (c *Column) UnsetCharset() *Column {\n\tdel(&c.Attrs, &Charset{})\n\treturn c\n}\n\n// SetCollation sets or appends the Collation attribute\n// to the column with the given value.\nfunc (c *Column) SetCollation(v string) *Column {\n\tReplaceOrAppend(&c.Attrs, &Collation{V: v})\n\treturn c\n}\n\n// UnsetCollation the Collation attribute.\nfunc (c *Column) UnsetCollation() *Column {\n\tdel(&c.Attrs, &Collation{})\n\treturn c\n}\n\n// SetComment sets or appends the Comment attribute\n// to the column with the given value.\nfunc (c *Column) SetComment(v string) *Column {\n\tReplaceOrAppend(&c.Attrs, &Comment{Text: v})\n\treturn c\n}\n\n// SetGeneratedExpr sets or appends the GeneratedExpr attribute.\nfunc (c *Column) SetGeneratedExpr(x *GeneratedExpr) *Column {\n\tReplaceOrAppend(&c.Attrs, x)\n\treturn c\n}\n\n// AddAttrs adds additional attributes to the column.\nfunc (c *Column) AddAttrs(attrs ...Attr) *Column {\n\tc.Attrs = append(c.Attrs, attrs...)\n\treturn c\n}\n\n// AddIndexes appends the references to the indexes this column is part of.\nfunc (c *Column) AddIndexes(indexes ...*Index) *Column {\n\tfor _, idx := range indexes {\n\t\tif !slices.Contains(c.Indexes, idx) {\n\t\t\tc.Indexes = append(c.Indexes, idx)\n\t\t}\n\t}\n\treturn c\n}\n\n// NewCheck creates a new check.\nfunc NewCheck() *Check {\n\treturn &Check{}\n}\n\n// SetName configures the name of the check constraint.\nfunc (c *Check) SetName(name string) *Check {\n\tc.Name = name\n\treturn c\n}\n\n// SetExpr configures the expression of the check constraint.\nfunc (c *Check) SetExpr(expr string) *Check {\n\tc.Expr = expr\n\treturn c\n}\n\n// AddAttrs adds additional attributes to the check constraint.\nfunc (c *Check) AddAttrs(attrs ...Attr) *Check {\n\tc.Attrs = append(c.Attrs, attrs...)\n\treturn c\n}\n\n// NewIndex creates a new index with the given name.\nfunc NewIndex(name string) *Index {\n\treturn &Index{Name: name}\n}\n\n// NewUniqueIndex creates a new unique index with the given name.\nfunc NewUniqueIndex(name string) *Index {\n\treturn NewIndex(name).SetUnique(true)\n}\n\n// NewPrimaryKey creates a new primary-key index\n// for the given columns.\nfunc NewPrimaryKey(columns ...*Column) *Index {\n\treturn new(Index).SetUnique(true).AddColumns(columns...)\n}\n\n// SetName configures the name of the index.\nfunc (i *Index) SetName(name string) *Index {\n\ti.Name = name\n\treturn i\n}\n\n// SetUnique configures the uniqueness of the index.\nfunc (i *Index) SetUnique(b bool) *Index {\n\ti.Unique = b\n\treturn i\n}\n\n// SetTable configures the table of the index.\nfunc (i *Index) SetTable(t *Table) *Index {\n\ti.Table = t\n\treturn i\n}\n\n// SetComment sets or appends the Comment attribute\n// to the index with the given value.\nfunc (i *Index) SetComment(v string) *Index {\n\tReplaceOrAppend(&i.Attrs, &Comment{Text: v})\n\treturn i\n}\n\n// AddAttrs adds additional attributes to the index.\nfunc (i *Index) AddAttrs(attrs ...Attr) *Index {\n\ti.Attrs = append(i.Attrs, attrs...)\n\treturn i\n}\n\n// AddColumns adds the columns to index parts.\nfunc (i *Index) AddColumns(columns ...*Column) *Index {\n\tfor _, c := range columns {\n\t\tif !c.hasIndex(i) {\n\t\t\tc.Indexes = append(c.Indexes, i)\n\t\t}\n\t\ti.Parts = append(i.Parts, &IndexPart{SeqNo: len(i.Parts), C: c})\n\t}\n\treturn i\n}\n\nfunc (c *Column) hasIndex(idx *Index) bool {\n\tfor i := range c.Indexes {\n\t\tif c.Indexes[i] == idx {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// AddExprs adds the expressions to index parts.\nfunc (i *Index) AddExprs(exprs ...Expr) *Index {\n\tfor _, x := range exprs {\n\t\ti.Parts = append(i.Parts, &IndexPart{SeqNo: len(i.Parts), X: x})\n\t}\n\treturn i\n}\n\n// AddParts appends the given parts.\nfunc (i *Index) AddParts(parts ...*IndexPart) *Index {\n\tfor _, p := range parts {\n\t\tif p.C != nil && !p.C.hasIndex(i) {\n\t\t\tp.C.Indexes = append(p.C.Indexes, i)\n\t\t}\n\t\tp.SeqNo = len(i.Parts)\n\t\ti.Parts = append(i.Parts, p)\n\t}\n\treturn i\n}\n\n// NewIndexPart creates a new index part.\nfunc NewIndexPart() *IndexPart { return &IndexPart{} }\n\n// NewColumnPart creates a new index part with the given column.\nfunc NewColumnPart(c *Column) *IndexPart { return NewIndexPart().SetColumn(c) }\n\n// NewExprPart creates a new index part with the given expression.\nfunc NewExprPart(x Expr) *IndexPart { return NewIndexPart().SetExpr(x) }\n\n// SetDesc configures the \"DESC\" attribute of the key part.\nfunc (p *IndexPart) SetDesc(b bool) *IndexPart {\n\tp.Desc = b\n\treturn p\n}\n\n// AddAttrs adds and additional attributes to the index-part.\nfunc (p *IndexPart) AddAttrs(attrs ...Attr) *IndexPart {\n\tp.Attrs = append(p.Attrs, attrs...)\n\treturn p\n}\n\n// SetColumn sets the column of the index-part.\nfunc (p *IndexPart) SetColumn(c *Column) *IndexPart {\n\tp.C = c\n\treturn p\n}\n\n// SetExpr sets the expression of the index-part.\nfunc (p *IndexPart) SetExpr(x Expr) *IndexPart {\n\tp.X = x\n\treturn p\n}\n\n// NewForeignKey creates a new foreign-key with\n// the given constraints/symbol name.\nfunc NewForeignKey(symbol string) *ForeignKey {\n\treturn &ForeignKey{Symbol: symbol}\n}\n\n// SetTable configures the table that holds the foreign-key (child table).\nfunc (f *ForeignKey) SetTable(t *Table) *ForeignKey {\n\tf.Table = t\n\treturn f\n}\n\n// AddColumns appends columns to the child-table columns.\nfunc (f *ForeignKey) AddColumns(columns ...*Column) *ForeignKey {\n\tfor _, c := range columns {\n\t\tif !c.hasForeignKey(f) {\n\t\t\tc.ForeignKeys = append(c.ForeignKeys, f)\n\t\t}\n\t}\n\tf.Columns = append(f.Columns, columns...)\n\treturn f\n}\n\nfunc (c *Column) hasForeignKey(fk *ForeignKey) bool {\n\tfor i := range c.ForeignKeys {\n\t\tif c.ForeignKeys[i] == fk {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// SetRefTable configures the referenced/parent table.\nfunc (f *ForeignKey) SetRefTable(t *Table) *ForeignKey {\n\tf.RefTable = t\n\treturn f\n}\n\n// AddRefColumns appends columns to the parent-table columns.\nfunc (f *ForeignKey) AddRefColumns(columns ...*Column) *ForeignKey {\n\tf.RefColumns = append(f.RefColumns, columns...)\n\treturn f\n}\n\n// SetOnUpdate sets the ON UPDATE constraint action.\nfunc (f *ForeignKey) SetOnUpdate(o ReferenceOption) *ForeignKey {\n\tf.OnUpdate = o\n\treturn f\n}\n\n// SetOnDelete sets the ON DELETE constraint action.\nfunc (f *ForeignKey) SetOnDelete(o ReferenceOption) *ForeignKey {\n\tf.OnDelete = o\n\treturn f\n}\n\n// AddAttrs adds additional attributes to the schema.\nfunc (f *ForeignKey) AddAttrs(attrs ...Attr) *ForeignKey {\n\tf.Attrs = append(f.Attrs, attrs...)\n\treturn f\n}\n\n// AddDeps adds the given objects as dependencies to the function.\nfunc (f *Func) AddDeps(objs ...Object) *Func {\n\tf.Deps = append(f.Deps, objs...)\n\taddRefs(f, objs)\n\treturn f\n}\n\n// RemoveDep removes the given object from the function dependencies.\nfunc (f *Func) RemoveDep(o Object) {\n\tf.Deps = removeObj(f.Deps, o)\n}\n\n// AddRefs adds references to the function.\nfunc (f *Func) AddRefs(refs ...Object) {\n\tf.Refs = append(f.Refs, refs...)\n\tSortRefs(f.Refs)\n}\n\n// AddDeps adds the given objects as dependencies to the procedure.\nfunc (p *Proc) AddDeps(objs ...Object) *Proc {\n\tp.Deps = append(p.Deps, objs...)\n\taddRefs(p, objs)\n\treturn p\n}\n\n// RemoveDep removes the given object from the procedure dependencies.\nfunc (p *Proc) RemoveDep(o Object) {\n\tp.Deps = removeObj(p.Deps, o)\n}\n\n// AddRefs adds references to the procedure.\nfunc (p *Proc) AddRefs(refs ...Object) {\n\tp.Refs = append(p.Refs, refs...)\n\tSortRefs(p.Refs)\n}\n\n// ReplaceOrAppend searches an attribute of the same type as v in\n// the list and replaces it. Otherwise, v is appended to the list.\nfunc ReplaceOrAppend(attrs *[]Attr, v Attr) {\n\tt := reflect.TypeOf(v)\n\tfor i := range *attrs {\n\t\tif reflect.TypeOf((*attrs)[i]) == t {\n\t\t\t(*attrs)[i] = v\n\t\t\treturn\n\t\t}\n\t}\n\t*attrs = append(*attrs, v)\n}\n\n// RemoveAttr returns a new slice where all attributes of type T are filtered.\nfunc RemoveAttr[T Attr](attrs []Attr) []Attr {\n\tf := make([]Attr, 0, len(attrs))\n\tfor _, a := range attrs {\n\t\tif _, ok := a.(T); !ok {\n\t\t\tf = append(f, a)\n\t\t}\n\t}\n\treturn f\n}\n\n// NewFilePos creates a file position.\nfunc NewFilePos(name string) *Pos {\n\treturn &Pos{\n\t\tFilename: name,\n\t}\n}\n\n// SetStart of the position.\nfunc (p *Pos) SetStart(s struct{ Line, Column, Byte int }) *Pos {\n\tp.Start = s\n\treturn p\n}\n\n// SetEnd of the position.\nfunc (p *Pos) SetEnd(e struct{ Line, Column, Byte int }) *Pos {\n\tp.End = e\n\treturn p\n}\n\n// del searches an attribute of the same type as v in\n// the list and deletes it.\nfunc del(attrs *[]Attr, v Attr) {\n\tt := reflect.TypeOf(v)\n\tfor i := range *attrs {\n\t\tif reflect.TypeOf((*attrs)[i]) == t {\n\t\t\t*attrs = append((*attrs)[:i], (*attrs)[i+1:]...)\n\t\t\treturn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "sql/schema/dsl_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schema_test\n\nimport (\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTable_AddColumns(t *testing.T) {\n\tusers := schema.NewTable(\"users\").\n\t\tSetComment(\"users table\").\n\t\tAddColumns(\n\t\t\tschema.NewBoolColumn(\"active\", \"bool\"),\n\t\t\tschema.NewDecimalColumn(\"age\", \"decimal\"),\n\t\t\tschema.NewNullStringColumn(\"name\", \"varchar\", schema.StringSize(255)),\n\t\t)\n\trequire.Equal(\n\t\tt,\n\t\t&schema.Table{\n\t\t\tName: \"users\",\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Comment{Text: \"users table\"},\n\t\t\t},\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{Name: \"active\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"bool\"}}},\n\t\t\t\t{Name: \"age\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"decimal\"}}},\n\t\t\t\t{Name: \"name\", Type: &schema.ColumnType{Null: true, Type: &schema.StringType{T: \"varchar\", Size: 255}}},\n\t\t\t},\n\t\t},\n\t\tusers,\n\t)\n}\n\nfunc TestSchema_AddTables(t *testing.T) {\n\tuserColumns := []*schema.Column{\n\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\tschema.NewBoolColumn(\"active\", \"boolean\"),\n\t\tschema.NewNullStringColumn(\"name\", \"varchar\", schema.StringSize(255)),\n\t\tschema.NewTimeColumn(\"registered_at\", \"timestamp\", schema.TimePrecision(6)),\n\t\tschema.NewTimeColumn(\"open_time\", \"time\", schema.TimeScale(2)),\n\t}\n\tusers := schema.NewTable(\"users\").\n\t\tAddColumns(userColumns...).\n\t\tSetPrimaryKey(schema.NewPrimaryKey(userColumns[0])).\n\t\tSetComment(\"users table\").\n\t\tAddIndexes(\n\t\t\tschema.NewUniqueIndex(\"unique_name\").\n\t\t\t\tAddColumns(userColumns[2]).\n\t\t\t\tSetComment(\"index comment\"),\n\t\t)\n\tpostColumns := []*schema.Column{\n\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\tschema.NewStringColumn(\"text\", \"longtext\"),\n\t\tschema.NewNullIntColumn(\"author_id\", \"int\"),\n\t}\n\tposts := schema.NewTable(\"posts\").\n\t\tAddColumns(postColumns...).\n\t\tSetPrimaryKey(schema.NewPrimaryKey(postColumns[0])).\n\t\tSetComment(\"posts table\").\n\t\tAddForeignKeys(\n\t\t\tschema.NewForeignKey(\"author_id\").\n\t\t\t\tAddColumns(postColumns[2]).\n\t\t\t\tSetRefTable(users).\n\t\t\t\tAddRefColumns(userColumns[0]).\n\t\t\t\tSetOnDelete(schema.Cascade).\n\t\t\t\tSetOnUpdate(schema.SetNull),\n\t\t)\n\trequire.Equal(\n\t\tt,\n\t\tfunc() *schema.Schema {\n\t\t\tp := 6\n\t\t\tscale := 2\n\t\t\ts := &schema.Schema{Name: \"public\"}\n\t\t\tusers := &schema.Table{\n\t\t\t\tName:   \"users\",\n\t\t\t\tSchema: s,\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Comment{Text: \"users table\"},\n\t\t\t\t},\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t{Name: \"active\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}}},\n\t\t\t\t\t{Name: \"name\", Type: &schema.ColumnType{Null: true, Type: &schema.StringType{T: \"varchar\", Size: 255}}},\n\t\t\t\t\t{Name: \"registered_at\", Type: &schema.ColumnType{Null: false, Type: &schema.TimeType{T: \"timestamp\", Precision: &p}}},\n\t\t\t\t\t{Name: \"open_time\", Type: &schema.ColumnType{Null: false, Type: &schema.TimeType{T: \"time\", Precision: nil, Scale: &scale}}},\n\t\t\t\t},\n\t\t\t}\n\t\t\ts.Tables = append(s.Tables, users)\n\t\t\tusers.PrimaryKey = &schema.Index{Unique: true, Parts: []*schema.IndexPart{{C: users.Columns[0]}}}\n\t\t\tusers.PrimaryKey.Table = users\n\t\t\tusers.Columns[0].Indexes = append(users.Columns[0].Indexes, users.PrimaryKey)\n\t\t\tusers.Indexes = append(users.Indexes, &schema.Index{\n\t\t\t\tName:   \"unique_name\",\n\t\t\t\tUnique: true,\n\t\t\t\tParts:  []*schema.IndexPart{{C: users.Columns[2]}},\n\t\t\t\tAttrs:  []schema.Attr{&schema.Comment{Text: \"index comment\"}},\n\t\t\t})\n\t\t\tusers.Indexes[0].Table = users\n\t\t\tusers.Columns[2].Indexes = users.Indexes\n\n\t\t\tposts := &schema.Table{\n\t\t\t\tName:   \"posts\",\n\t\t\t\tSchema: s,\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Comment{Text: \"posts table\"},\n\t\t\t\t},\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t{Name: \"text\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"longtext\"}}},\n\t\t\t\t\t{Name: \"author_id\", Type: &schema.ColumnType{Null: true, Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t},\n\t\t\t}\n\t\t\ts.Tables = append(s.Tables, posts)\n\t\t\tposts.PrimaryKey = &schema.Index{Unique: true, Parts: []*schema.IndexPart{{C: posts.Columns[0]}}}\n\t\t\tposts.PrimaryKey.Table = posts\n\t\t\tposts.Columns[0].Indexes = append(posts.Columns[0].Indexes, posts.PrimaryKey)\n\t\t\tposts.ForeignKeys = append(posts.ForeignKeys, &schema.ForeignKey{\n\t\t\t\tSymbol:     \"author_id\",\n\t\t\t\tTable:      posts,\n\t\t\t\tColumns:    posts.Columns[2:],\n\t\t\t\tRefTable:   users,\n\t\t\t\tRefColumns: users.Columns[0:1],\n\t\t\t\tOnDelete:   schema.Cascade,\n\t\t\t\tOnUpdate:   schema.SetNull,\n\t\t\t})\n\t\t\tposts.Columns[2].ForeignKeys = posts.ForeignKeys\n\t\t\treturn s\n\t\t}(),\n\t\tschema.New(\"public\").AddTables(users, posts),\n\t)\n}\n\nfunc TestSchema_Views(t *testing.T) {\n\ts := schema.New(\"public\")\n\tv1, v2 := schema.NewView(\"v1\", \"SELECT 1\"), schema.NewView(\"v2\", \"SELECT 2\")\n\ts.AddViews(v1, v2)\n\trequire.Equal(t, []*schema.View{v1, v2}, s.Views)\n\tv1.AddDeps(v2)\n\trequire.Equal(t, []schema.Object{v2}, v1.Deps)\n\trequire.Equal(t, []schema.Object{v1}, v2.Refs)\n}\n\nfunc TestSchema_SetCharset(t *testing.T) {\n\ts := schema.New(\"public\")\n\trequire.Empty(t, s.Attrs)\n\ts.SetCharset(\"utf8mb4\")\n\trequire.Len(t, s.Attrs, 1)\n\trequire.Equal(t, &schema.Charset{V: \"utf8mb4\"}, s.Attrs[0])\n\ts.SetCharset(\"latin1\")\n\trequire.Len(t, s.Attrs, 1)\n\trequire.Equal(t, &schema.Charset{V: \"latin1\"}, s.Attrs[0])\n\ts.UnsetCharset()\n\trequire.Empty(t, s.Attrs)\n}\n\nfunc TestSchema_SetCollation(t *testing.T) {\n\ts := schema.New(\"public\")\n\trequire.Empty(t, s.Attrs)\n\ts.SetCollation(\"utf8mb4_general_ci\")\n\trequire.Len(t, s.Attrs, 1)\n\trequire.Equal(t, &schema.Collation{V: \"utf8mb4_general_ci\"}, s.Attrs[0])\n\ts.SetCollation(\"latin1_swedish_ci\")\n\trequire.Len(t, s.Attrs, 1)\n\trequire.Equal(t, &schema.Collation{V: \"latin1_swedish_ci\"}, s.Attrs[0])\n\ts.UnsetCollation()\n\trequire.Empty(t, s.Attrs)\n}\n\nfunc TestSchema_SetComment(t *testing.T) {\n\ts := schema.New(\"public\")\n\trequire.Empty(t, s.Attrs)\n\ts.SetComment(\"1\")\n\trequire.Len(t, s.Attrs, 1)\n\trequire.Equal(t, &schema.Comment{Text: \"1\"}, s.Attrs[0])\n\ts.SetComment(\"2\")\n\trequire.Len(t, s.Attrs, 1)\n\trequire.Equal(t, &schema.Comment{Text: \"2\"}, s.Attrs[0])\n}\n\nfunc TestSchema_SetGeneratedExpr(t *testing.T) {\n\tc := schema.NewIntColumn(\"c\", \"int\")\n\trequire.Empty(t, c.Attrs)\n\tx := &schema.GeneratedExpr{Expr: \"d*2\", Type: \"VIRTUAL\"}\n\tc.SetGeneratedExpr(x)\n\trequire.Equal(t, []schema.Attr{x}, c.Attrs)\n}\n\nfunc TestCheck(t *testing.T) {\n\tenforced := &struct{ schema.Attr }{}\n\ttbl := schema.NewTable(\"table\").\n\t\tAddColumns(\n\t\t\tschema.NewColumn(\"price1\"),\n\t\t\tschema.NewColumn(\"price2\"),\n\t\t)\n\trequire.Empty(t, tbl.Attrs)\n\ttbl.AddChecks(\n\t\tschema.NewCheck().\n\t\t\tSetName(\"unique prices\").\n\t\t\tSetExpr(\"price1 <> price2\"),\n\t\tschema.NewCheck().\n\t\t\tSetExpr(\"price1 > 0\").\n\t\t\tAddAttrs(enforced),\n\t)\n\trequire.Len(t, tbl.Attrs, 2)\n\trequire.Equal(t, &schema.Check{\n\t\tName: \"unique prices\",\n\t\tExpr: \"price1 <> price2\",\n\t}, tbl.Attrs[0])\n\trequire.Equal(t, &schema.Check{\n\t\tExpr:  \"price1 > 0\",\n\t\tAttrs: []schema.Attr{enforced},\n\t}, tbl.Attrs[1])\n}\n\nfunc TestRemoveAttr(t *testing.T) {\n\tu := schema.NewTable(\"users\")\n\trequire.Empty(t, u.Attrs)\n\tu.SetComment(\"users table\")\n\trequire.Len(t, u.Attrs, 1)\n\tu.Attrs = schema.RemoveAttr[*schema.Comment](u.Attrs)\n\trequire.Empty(t, u.Attrs)\n\n\tu.AddAttrs(&schema.Comment{}, &schema.Comment{})\n\trequire.Len(t, u.Attrs, 2)\n\tu.Attrs = schema.RemoveAttr[*schema.Comment](u.Attrs)\n\trequire.Empty(t, u.Attrs)\n\n\tu.SetCharset(\"charset\")\n\tu.SetComment(\"users table\")\n\tu.SetCollation(\"collation\")\n\tu.Attrs = schema.RemoveAttr[*schema.Comment](u.Attrs)\n\trequire.Len(t, u.Attrs, 2)\n\trequire.Equal(t, &schema.Charset{V: \"charset\"}, u.Attrs[0])\n\trequire.Equal(t, &schema.Collation{V: \"collation\"}, u.Attrs[1])\n\tu.Attrs = schema.RemoveAttr[*schema.Collation](u.Attrs)\n\trequire.Len(t, u.Attrs, 1)\n\trequire.Equal(t, &schema.Charset{V: \"charset\"}, u.Attrs[0])\n}\n"
  },
  {
    "path": "sql/schema/exclude_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage schema\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n)\n\n// ExcludeRealm filters resources in the realm based on the given patterns.\nfunc ExcludeRealm(r *Realm, patterns []string) (*Realm, error) {\n\tif len(patterns) == 0 {\n\t\treturn r, nil\n\t}\n\tglobs, err := split(patterns)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor _, g := range globs {\n\t\t// Realm objects are top-level\n\t\t// resources, must like schemas.\n\t\tif len(g) == 1 {\n\t\t\tif r.Objects, err = excludeObjects(r.Objects, g); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\tvar schemas []*Schema\nFilter:\n\tfor _, s := range r.Schemas {\n\t\tfor i, g := range globs {\n\t\t\tif len(g) > 3 {\n\t\t\t\treturn nil, fmt.Errorf(\"too many parts in pattern: %q\", patterns[i])\n\t\t\t}\n\t\t\tif globS, exclude := excludeType(typeS, g[0]); exclude {\n\t\t\t\tmatch, err := filepath.Match(globS, s.Name)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif match {\n\t\t\t\t\t// In case there is a match, and it is\n\t\t\t\t\t// a single glob we exclude this\n\t\t\t\t\tif len(g) == 1 {\n\t\t\t\t\t\tcontinue Filter\n\t\t\t\t\t}\n\t\t\t\t\tif err := excludeS(s, g[1:]); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tschemas = append(schemas, s)\n\t}\n\tr.Schemas = schemas\n\treturn r, nil\n}\n\n// ExcludeSchema filters resources in the schema based on the given patterns.\nfunc ExcludeSchema(s *Schema, patterns []string) (*Schema, error) {\n\tif len(patterns) == 0 {\n\t\treturn s, nil\n\t}\n\tif s.Realm == nil {\n\t\treturn nil, fmt.Errorf(\"missing realm for schema %q\", s.Name)\n\t}\n\tqualified := make([]string, len(patterns))\n\tfor i, p := range patterns {\n\t\tqualified[i] = fmt.Sprintf(\"%s.%s\", s.Name, p)\n\t}\n\tif _, err := ExcludeRealm(s.Realm, qualified); err != nil {\n\t\treturn nil, err\n\t}\n\treturn s, nil\n}\n\n// split parses the list of patterns into chain of resource-globs.\n// For example, 's*.t.*' is split to ['s*', 't', *].\nfunc split(patterns []string) ([][]string, error) {\n\tglobs := make([][]string, len(patterns))\n\tfor i, p := range patterns {\n\t\tr := csv.NewReader(strings.NewReader(p))\n\t\tr.Comma = '.'\n\t\tswitch parts, err := r.ReadAll(); {\n\t\tcase err != nil:\n\t\t\treturn nil, err\n\t\tcase len(parts) != 1:\n\t\t\treturn nil, fmt.Errorf(\"unexpected pattern: %q\", p)\n\t\tcase len(parts[0]) == 0:\n\t\t\treturn nil, fmt.Errorf(\"empty pattern: %q\", p)\n\t\tdefault:\n\t\t\tglobs[i] = parts[0]\n\t\t}\n\t}\n\treturn globs, nil\n}\n\nfunc excludeS(s *Schema, glob []string) (err error) {\n\tif s.Objects, err = excludeObjects(s.Objects, glob); err != nil {\n\t\treturn err\n\t}\n\tif globT, exclude := excludeType(typeT, glob[0]); exclude {\n\t\tvar tables []*Table\n\t\tfor _, t := range s.Tables {\n\t\t\tmatch, err := filepath.Match(globT, t.Name)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif match {\n\t\t\t\t// In case there is a match, and it is\n\t\t\t\t// a single glob we exclude this table.\n\t\t\t\tif len(glob) == 1 {\n\t\t\t\t\tdetachObject(t, t.Refs)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif err := excludeT(t, glob[1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\t// No match or glob has more than one pattern.\n\t\t\ttables = append(tables, t)\n\t\t}\n\t\ts.Tables = tables\n\t}\n\tif globV, exclude := excludeType(typeV, glob[0]); exclude {\n\t\tvar views []*View\n\t\tfor _, v := range s.Views {\n\t\t\tmatch, err := filepath.Match(globV, v.Name)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif match {\n\t\t\t\tif len(glob) == 1 {\n\t\t\t\t\tdetachObject(v, v.Refs)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif err := excludeV(v, glob[1]); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tviews = append(views, v)\n\t\t}\n\t\ts.Views = views\n\t}\n\tif globF, exclude := excludeType(typeFn, glob[0]); exclude && len(glob) == 1 {\n\t\tvar err error\n\t\ts.Funcs, err = filter(s.Funcs, func(f *Func) (bool, error) {\n\t\t\tif match, err := filepath.Match(globF, f.Name); !match || err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tdetachObject(f, f.Refs)\n\t\t\treturn true, nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif globP, exclude := excludeType(typePr, glob[0]); exclude && len(glob) == 1 {\n\t\tvar err error\n\t\ts.Procs, err = filter(s.Procs, func(p *Proc) (bool, error) {\n\t\t\tif match, err := filepath.Match(globP, p.Name); !match || err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tdetachObject(p, p.Refs)\n\t\t\treturn true, nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc excludeT(t *Table, pattern string) (err error) {\n\tex := make(map[*Index]struct{})\n\tef := make(map[*ForeignKey]struct{})\n\tif p, exclude := excludeType(typeC, pattern); exclude {\n\t\tt.Columns, err = filter(t.Columns, func(c *Column) (bool, error) {\n\t\t\tmatch, err := filepath.Match(p, c.Name)\n\t\t\tif !match || err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\tfor _, idx := range c.Indexes {\n\t\t\t\tex[idx] = struct{}{}\n\t\t\t}\n\t\t\tfor _, fk := range c.ForeignKeys {\n\t\t\t\tef[fk] = struct{}{}\n\t\t\t}\n\t\t\treturn true, nil\n\t\t})\n\t}\n\tif p, exclude := excludeType(typeI, pattern); exclude {\n\t\tt.Indexes, err = filter(t.Indexes, func(idx *Index) (bool, error) {\n\t\t\tif _, ok := ex[idx]; ok {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t\treturn filepath.Match(p, idx.Name)\n\t\t})\n\t}\n\tif p, exclude := excludeType(typeF, pattern); exclude {\n\t\tt.ForeignKeys, err = filter(t.ForeignKeys, func(fk *ForeignKey) (bool, error) {\n\t\t\tif _, ok := ef[fk]; ok {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t\treturn filepath.Match(p, fk.Symbol)\n\t\t})\n\t}\n\tif p, exclude := excludeType(typeTg, pattern); exclude {\n\t\tt.Triggers, err = filter(t.Triggers, func(t *Trigger) (bool, error) {\n\t\t\treturn filepath.Match(p, t.Name)\n\t\t})\n\t}\n\tif p, exclude := excludeType(typeK, pattern); exclude {\n\t\tt.Attrs, err = filter(t.Attrs, func(a Attr) (bool, error) {\n\t\t\tc, ok := a.(*Check)\n\t\t\tif !ok {\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t\tmatch, err := filepath.Match(p, c.Name)\n\t\t\tif !match || err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\treturn true, nil\n\t\t})\n\t}\n\treturn\n}\n\nfunc excludeV(v *View, pattern string) (err error) {\n\tif p, exclude := excludeType(typeC, pattern); exclude {\n\t\tv.Columns, err = filter(v.Columns, func(c *Column) (bool, error) {\n\t\t\tmatch, err := filepath.Match(p, c.Name)\n\t\t\tif !match || err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\treturn true, nil\n\t\t})\n\t}\n\tif p, exclude := excludeType(typeTg, pattern); exclude {\n\t\tv.Triggers, err = filter(v.Triggers, func(t *Trigger) (bool, error) {\n\t\t\treturn filepath.Match(p, t.Name)\n\t\t})\n\t}\n\treturn\n}\n\n// SpecTypeNamer is an interface that allows to get the spec type and name of the object.\ntype SpecTypeNamer interface {\n\tSpecType() string\n\tSpecName() string\n}\n\nfunc excludeObjects(all []Object, glob []string) ([]Object, error) {\n\tvar (\n\t\tobjects = make([]Object, 0, len(all))\n\t\tt2glob  = make(map[string]struct {\n\t\t\tglob    string\n\t\t\texclude bool\n\t\t})\n\t)\n\tfor _, o := range all {\n\t\tnt, ok := o.(SpecTypeNamer)\n\t\tif !ok {\n\t\t\tobjects = append(objects, o)\n\t\t\tcontinue\n\t\t}\n\t\tcache, ok := t2glob[nt.SpecType()]\n\t\tif !ok {\n\t\t\tcache.glob, cache.exclude = excludeType(nt.SpecType(), glob[0])\n\t\t\tt2glob[nt.SpecType()] = cache\n\t\t}\n\t\tif cache.exclude {\n\t\t\tmatch, err := filepath.Match(cache.glob, nt.SpecName())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\t// No match or glob has more than one pattern.\n\t\t\tif !match || len(glob) != 1 {\n\t\t\t\tobjects = append(objects, o)\n\t\t\t}\n\t\t} else {\n\t\t\tobjects = append(objects, o)\n\t\t}\n\t}\n\treturn objects, nil\n}\n\nconst (\n\ttypeV  = \"view\"\n\ttypeT  = \"table\"\n\ttypeS  = \"schema\"\n\ttypeC  = \"column\"\n\ttypeI  = \"index\"\n\ttypeF  = \"fk\"\n\ttypeK  = \"check\"\n\ttypeTg = \"trigger\"\n\ttypeFn = \"function\"\n\ttypePr = \"procedure\"\n)\n\nvar reType = regexp.MustCompile(`\\[type=([a-z|_]+)+\\]$`)\n\nfunc excludeType(t, v string) (string, bool) {\n\tmatches := reType.FindStringSubmatch(v)\n\tif len(matches) != 2 {\n\t\treturn v, true\n\t}\n\tv = strings.TrimSuffix(v, matches[0])\n\tfor _, m := range strings.Split(matches[1], \"|\") {\n\t\tif m == t {\n\t\t\t// Selector matches.\n\t\t\treturn v, true\n\t\t}\n\t}\n\t// There is a selector with no match.\n\treturn v, false\n}\n\nfunc filter[T any](s []T, f func(T) (bool, error)) ([]T, error) {\n\tr := make([]T, 0, len(s))\n\tfor i := range s {\n\t\tmatch, err := f(s[i])\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif !match {\n\t\t\tr = append(r, s[i])\n\t\t}\n\t}\n\treturn r, nil\n}\n\n// detach the given object from all its references.\nfunc detachObject(o Object, refs []Object) {\n\tfor _, r := range refs {\n\t\tif d, ok := r.(DepRemover); ok {\n\t\t\td.RemoveDep(o)\n\t\t}\n\t}\n}\n\n// IncludeRealm is a no-op for the community version.\nfunc IncludeRealm(r *Realm, _ []string) (*Realm, error) {\n\treturn r, nil // Unimplemented.\n}\n\n// IncludeSchema is a no-op for the community version.\nfunc IncludeSchema(s *Schema, _ []string) (*Schema, error) {\n\treturn s, nil // Unimplemented.\n}\n"
  },
  {
    "path": "sql/schema/inspect.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schema\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n)\n\n// A NotExistError wraps another error to retain its original text\n// but makes it possible to the migrator to catch it.\ntype NotExistError struct {\n\tErr error\n}\n\nfunc (e NotExistError) Error() string { return e.Err.Error() }\n\n// IsNotExistError reports if an error is a NotExistError.\nfunc IsNotExistError(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tvar e *NotExistError\n\treturn errors.As(err, &e)\n}\n\n// ExecQuerier wraps the two standard sql.DB methods.\ntype ExecQuerier interface {\n\tQueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)\n\tExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)\n}\n\n// An InspectMode controls the amount and depth of information returned on inspection.\ntype InspectMode uint\n\nconst (\n\t// InspectSchemas enables schema inspection.\n\tInspectSchemas InspectMode = 1 << iota\n\n\t// InspectTables enables schema tables inspection including\n\t// all its child resources (e.g. columns or indexes).\n\tInspectTables\n\n\t// InspectViews enables schema views inspection.\n\tInspectViews\n\n\t// InspectFuncs enables schema functions / procedures inspection.\n\tInspectFuncs\n\n\t// InspectTypes enables schema types inspection.\n\tInspectTypes\n\n\t// InspectObjects enables inspection of database specific\n\t// objects like sequences and extensions.\n\tInspectObjects\n\n\t// InspectTriggers enables schema triggers inspection.\n\tInspectTriggers\n)\n\n// Is reports whether the given mode is enabled.\nfunc (m InspectMode) Is(i InspectMode) bool { return m&i != 0 }\n\ntype (\n\t// InspectOptions describes options for Inspector.\n\tInspectOptions struct {\n\t\t// Mode defines the amount of information returned by InspectSchema.\n\t\t// If zero, InspectSchema inspects whole resources in the schema.\n\t\tMode InspectMode\n\n\t\t// Tables to inspect. Empty means all tables in the schema.\n\t\tTables []string\n\n\t\t// Include defines a list of glob patterns used to filter resources for inspection.\n\t\t// If non-empty, only resources matching at least one of the patterns are considered.\n\t\t// After applying inclusion, the Exclude list is used to filter out resources.\n\t\t// The syntax used by the different drivers is implemented as follows:\n\t\t//\n\t\t//\tt   // include objects named 't'.\n\t\t//\t*   // include all schema objects (tables, views, etc.).\n\t\t//\tt.c // include column, index and foreign-key named 'c' in table 't'.\n\t\t//\tt.* // the last item defines the filtering; all resources under 't' are included.\n\t\t//\t*.c // the last item defines the filtering; all resources named 'c' are included in all tables.\n\t\t//\t*.* // the last item defines the filtering; all resources under all tables are included.\n\t\t//\n\t\t// If Include is empty, all resources are considered unless excluded.\n\t\tInclude []string\n\n\t\t// Exclude defines a list of glob patterns used to filter resources from inspection.\n\t\t// The syntax used by the different drivers is implemented as follows:\n\t\t//\n\t\t//\tt   // exclude table 't'.\n\t\t//\t*   // exclude all tables.\n\t\t//\tt.c // exclude column, index and foreign-key named 'c' in table 't'.\n\t\t//\tt.* // the last item defines the filtering; all resources under 't' are excluded.\n\t\t//\t*.c // the last item defines the filtering; all resourced named 'c' are excluded in all tables.\n\t\t//\t*.* // the last item defines the filtering; all resourced under all tables are excluded.\n\t\t//\n\t\tExclude []string\n\t}\n\n\t// InspectRealmOption describes options for RealmInspector.\n\tInspectRealmOption struct {\n\t\t// Mode defines the amount of information returned by InspectRealm.\n\t\t// If zero, InspectRealm inspects all schemas and their child resources.\n\t\tMode InspectMode\n\n\t\t// Schemas to inspect. Empty means all schemas in the realm.\n\t\tSchemas []string\n\n\t\t// Include defines a list of glob patterns used to filter resources for inspection.\n\t\t// If non-empty, only resources matching at least one of the patterns are considered.\n\t\t// After applying inclusion, the Exclude list is used to filter out resources.\n\t\t// The syntax used by the different drivers is implemented as follows:\n\t\t//\n\t\t//\ts       // include schema 's'.\n\t\t//\t*       // include all schemas.\n\t\t//\ts.t     // include table 't' under schema 's'.\n\t\t//\ts.*     // the last item defines the filtering; all tables under 's' are included.\n\t\t//\t*.t     // the last item defines the filtering; all tables named 't' are included in all schemas.\n\t\t//\t*.*     // the last item defines the filtering; all tables under all schemas are included.\n\t\t//\t*.*.c   // the last item defines the filtering; all resources named 'c' are included in all tables.\n\t\t//\t*.*.*   // the last item defines the filtering; all resources are included in all tables.\n\t\t//\n\t\t// If Include is empty, all resources are considered unless excluded.\n\t\tInclude []string\n\n\t\t// Exclude defines a list of glob patterns used to filter resources from inspection.\n\t\t// The syntax used by the different drivers is implemented as follows:\n\t\t//\n\t\t//\ts     // exclude schema 's'.\n\t\t//\t*     // exclude all schemas.\n\t\t//\ts.t   // exclude table 't' under schema 's'.\n\t\t//\ts.*   // the last item defines the filtering; all tables under 's' are excluded.\n\t\t//\t*.t   // the last item defines the filtering; all tables named 't' are excluded in all schemas.\n\t\t//\t*.*   // the last item defines the filtering; all tables under all schemas are excluded.\n\t\t//\t*.*.c // the last item defines the filtering; all resourced named 'c' are excluded in all tables.\n\t\t//\t*.*.* // the last item defines the filtering; all resources are excluded in all tables.\n\t\t//\n\t\tExclude []string\n\t}\n\n\t// Inspector is the interface implemented by the different database\n\t// drivers for inspecting schema or databases.\n\tInspector interface {\n\t\t// InspectSchema returns the schema description by its name. An empty name means the\n\t\t// \"attached schema\" (e.g. SCHEMA() in MySQL or CURRENT_SCHEMA() in PostgreSQL).\n\t\t// A NotExistError error is returned if the schema does not exist in the database.\n\t\tInspectSchema(ctx context.Context, name string, opts *InspectOptions) (*Schema, error)\n\n\t\t// InspectRealm returns the description of the connected database.\n\t\tInspectRealm(ctx context.Context, opts *InspectRealmOption) (*Realm, error)\n\t}\n)\n\n// Normalizer is the interface implemented by the different database drivers for\n// \"normalizing\" schema objects. i.e. converting schema objects defined in natural\n// form to their representation in the database. Thus, two schema objects are equal\n// if their normal forms are equal.\ntype Normalizer interface {\n\t// NormalizeSchema returns the normal representation of a schema.\n\tNormalizeSchema(context.Context, *Schema) (*Schema, error)\n\n\t// NormalizeRealm returns the normal representation of a database.\n\tNormalizeRealm(context.Context, *Realm) (*Realm, error)\n}\n"
  },
  {
    "path": "sql/schema/migrate.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schema\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"reflect\"\n\t\"time\"\n)\n\ntype (\n\t// A Change represents a schema change. The types below implement this\n\t// interface and can be used for describing schema changes.\n\t//\n\t// The Change interface can also be implemented outside this package\n\t// as follows:\n\t//\n\t//\ttype RenameType struct {\n\t//\t\tschema.Change\n\t//\t\tFrom, To string\n\t//\t}\n\t//\n\t//\tvar t schema.Change = &RenameType{From: \"old\", To: \"new\"}\n\t//\n\tChange interface {\n\t\tchange()\n\t}\n\n\t// Clause carries additional information that can be added\n\t// to schema changes. The Clause interface can be implemented\n\t// outside this package as follows:\n\t//\n\t//\ttype Authorization struct {\n\t//\t\tschema.Clause\n\t//\t\tUserName string\n\t//\t}\n\t//\n\t//\tvar c schema.Clause = &Authorization{UserName: \"a8m\"}\n\t//\n\tClause interface {\n\t\tclause()\n\t}\n\n\t// AddSchema describes a schema (named database) creation change.\n\t// Unlike table creation, schemas and their elements are described\n\t// with separate changes. For example, \"AddSchema\" and \"AddTable\"\n\tAddSchema struct {\n\t\tS     *Schema\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// DropSchema describes a schema (named database) removal change.\n\tDropSchema struct {\n\t\tS     *Schema\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// ModifySchema describes a modification change for schema attributes.\n\tModifySchema struct {\n\t\tS       *Schema\n\t\tChanges []Change\n\t}\n\n\t// AddTable describes a table creation change.\n\tAddTable struct {\n\t\tT     *Table\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// DropTable describes a table removal change.\n\tDropTable struct {\n\t\tT     *Table\n\t\tExtra []Clause // Extra clauses.\n\t}\n\n\t// ModifyTable describes a table modification change.\n\tModifyTable struct {\n\t\tT       *Table\n\t\tChanges []Change\n\t}\n\n\t// RenameTable describes a table rename change.\n\tRenameTable struct {\n\t\tFrom, To *Table\n\t}\n\n\t// AddView describes a view creation change.\n\tAddView struct {\n\t\tV     *View\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// DropView describes a view removal change.\n\tDropView struct {\n\t\tV     *View\n\t\tExtra []Clause // Extra clauses.\n\t}\n\n\t// ModifyView describes a view modification change.\n\tModifyView struct {\n\t\tFrom, To *View\n\t\t// Changes that are extra to the view definition.\n\t\t// For example, adding or dropping indexes.\n\t\tChanges []Change\n\t}\n\n\t// RenameView describes a view rename change.\n\tRenameView struct {\n\t\tFrom, To *View\n\t}\n\n\t// AddFunc describes a function creation change.\n\tAddFunc struct {\n\t\tF     *Func\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// DropFunc describes a function removal change.\n\tDropFunc struct {\n\t\tF     *Func\n\t\tExtra []Clause // Extra clauses.\n\t}\n\n\t// ModifyFunc describes a function modification change.\n\tModifyFunc struct {\n\t\tFrom, To *Func\n\t\t// Changes that are extra to the function definition.\n\t\t// For example, adding, dropping, or modifying attributes.\n\t\tChanges []Change\n\t}\n\n\t// RenameFunc describes a function rename change.\n\tRenameFunc struct {\n\t\tFrom, To *Func\n\t}\n\n\t// AddProc describes a procedure creation change.\n\tAddProc struct {\n\t\tP     *Proc\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// DropProc describes a procedure removal change.\n\tDropProc struct {\n\t\tP     *Proc\n\t\tExtra []Clause // Extra clauses.\n\t}\n\n\t// ModifyProc describes a procedure modification change.\n\tModifyProc struct {\n\t\tFrom, To *Proc\n\t\t// Changes that are extra to the procedure definition.\n\t\t// For example, adding, dropping, or modifying attributes.\n\t\tChanges []Change\n\t}\n\n\t// RenameProc describes a procedure rename change.\n\tRenameProc struct {\n\t\tFrom, To *Proc\n\t}\n\n\t// AddObject describes a generic object creation change.\n\tAddObject struct {\n\t\tO     Object\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// DropObject describes a generic object removal change.\n\tDropObject struct {\n\t\tO     Object\n\t\tExtra []Clause // Extra clauses.\n\t}\n\n\t// ModifyObject describes a generic object modification change.\n\t// Unlike tables changes, the diffing types are implemented by\n\t// the underlying driver.\n\tModifyObject struct {\n\t\tFrom, To Object\n\t}\n\n\t// RenameObject describes a generic object rename change.\n\tRenameObject struct {\n\t\tFrom, To Object\n\t}\n\n\t// AddTrigger describes a trigger creation change.\n\tAddTrigger struct {\n\t\tT     *Trigger\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// DropTrigger describes a trigger removal change.\n\tDropTrigger struct {\n\t\tT     *Trigger\n\t\tExtra []Clause // Extra clauses.\n\t}\n\n\t// ModifyTrigger describes a trigger modification change.\n\tModifyTrigger struct {\n\t\tFrom, To *Trigger\n\t\t// Changes that are extra to the trigger definition.\n\t\t// For example, adding, dropping, or modifying attributes.\n\t\tChanges []Change\n\t}\n\n\t// RenameTrigger describes a trigger rename change.\n\tRenameTrigger struct {\n\t\tFrom, To *Trigger\n\t}\n\n\t// AddColumn describes a column creation change.\n\tAddColumn struct {\n\t\tC *Column\n\t}\n\n\t// DropColumn describes a column removal change.\n\tDropColumn struct {\n\t\tC *Column\n\t}\n\n\t// ModifyColumn describes a change that modifies a column.\n\tModifyColumn struct {\n\t\tFrom, To *Column\n\t\tChange   ChangeKind\n\t\tExtra    []Clause // Extra clauses and options.\n\t}\n\n\t// RenameColumn describes a column rename change.\n\tRenameColumn struct {\n\t\tFrom, To *Column\n\t}\n\n\t// AddIndex describes an index creation change.\n\tAddIndex struct {\n\t\tI     *Index\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// DropIndex describes an index removal change.\n\tDropIndex struct {\n\t\tI     *Index\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// ModifyIndex describes an index modification.\n\tModifyIndex struct {\n\t\tFrom, To *Index\n\t\tChange   ChangeKind\n\t\tExtra    []Clause // Extra clauses and options.\n\t}\n\n\t// RenameIndex describes an index rename change.\n\tRenameIndex struct {\n\t\tFrom, To *Index\n\t}\n\n\t// AddPrimaryKey describes a primary-key creation change.\n\tAddPrimaryKey struct {\n\t\tP *Index\n\t}\n\n\t// DropPrimaryKey describes a primary-key removal change.\n\tDropPrimaryKey struct {\n\t\tP *Index\n\t}\n\n\t// ModifyPrimaryKey describes a primary-key modification.\n\tModifyPrimaryKey struct {\n\t\tFrom, To *Index\n\t\tChange   ChangeKind\n\t}\n\n\t// AddForeignKey describes a foreign-key creation change.\n\tAddForeignKey struct {\n\t\tF     *ForeignKey\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// DropForeignKey describes a foreign-key removal change.\n\tDropForeignKey struct {\n\t\tF     *ForeignKey\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// ModifyForeignKey describes a change that modifies a foreign-key.\n\tModifyForeignKey struct {\n\t\tFrom, To *ForeignKey\n\t\tChange   ChangeKind\n\t}\n\n\t// AddCheck describes a CHECK constraint creation change.\n\tAddCheck struct {\n\t\tC     *Check\n\t\tExtra []Clause // Extra clauses and options.\n\t}\n\n\t// DropCheck describes a CHECK constraint removal change.\n\tDropCheck struct {\n\t\tC *Check\n\t}\n\n\t// ModifyCheck describes a change that modifies a check.\n\tModifyCheck struct {\n\t\tFrom, To *Check\n\t\tChange   ChangeKind\n\t}\n\n\t// RenameConstraint describes an constraint rename change.\n\tRenameConstraint struct {\n\t\tFrom, To Object // PK, FK, Unique, Check, etc.\n\t}\n\n\t// AddAttr describes an attribute addition.\n\tAddAttr struct {\n\t\tA Attr\n\t}\n\n\t// DropAttr describes an attribute removal.\n\tDropAttr struct {\n\t\tA Attr\n\t}\n\n\t// ModifyAttr describes a change that modifies an element attribute.\n\tModifyAttr struct {\n\t\tFrom, To Attr\n\t}\n\n\t// IfExists represents a clause in a schema change that is commonly\n\t// supported by multiple statements (e.g. DROP TABLE or DROP SCHEMA).\n\tIfExists struct{}\n\n\t// IfNotExists represents a clause in a schema change that is commonly\n\t// supported by multiple statements (e.g. CREATE TABLE or CREATE SCHEMA).\n\tIfNotExists struct{}\n)\n\n// A ChangeKind describes a change kind that can be combined\n// using a set of flags. The zero kind is no change.\n//\n//go:generate stringer -type ChangeKind\ntype ChangeKind uint\n\nconst (\n\t// NoChange holds the zero value of a change kind.\n\tNoChange ChangeKind = 0\n\n\t// Common changes.\n\n\t// ChangeAttr describes attributes change of an element.\n\t// For example, a table CHECK was added or changed.\n\tChangeAttr ChangeKind = 1 << (iota - 1)\n\t// ChangeCharset describes character-set change.\n\tChangeCharset\n\t// ChangeCollate describes collation/encoding change.\n\tChangeCollate\n\t// ChangeComment describes comment chang (of any element).\n\tChangeComment\n\n\t// Column specific changes.\n\n\t// ChangeNull describe a change to the NULL constraint.\n\tChangeNull\n\t// ChangeType describe a column type change.\n\tChangeType\n\t// ChangeDefault describe a column default change.\n\tChangeDefault\n\t// ChangeGenerated describe a change to the generated expression.\n\tChangeGenerated\n\n\t// Index specific changes.\n\n\t// ChangeUnique describes a change to the uniqueness constraint.\n\t// For example, an index was changed from non-unique to unique.\n\tChangeUnique\n\t// ChangeParts describes a change to one or more of the index parts.\n\t// For example, index keeps its previous name, but the columns order\n\t// was changed.\n\tChangeParts\n\n\t// Foreign key specific changes.\n\n\t// ChangeColumn describes a change to the foreign-key (child) columns.\n\tChangeColumn\n\t// ChangeRefColumn describes a change to the foreign-key (parent) columns.\n\tChangeRefColumn\n\t// ChangeRefTable describes a change to the foreign-key (parent) table.\n\tChangeRefTable\n\t// ChangeUpdateAction describes a change to the foreign-key update action.\n\tChangeUpdateAction\n\t// ChangeDeleteAction describes a change to the foreign-key delete action.\n\tChangeDeleteAction\n)\n\n// List of diff modes.\nconst (\n\tDiffModeUnset         DiffMode = 1 << iota // Default, backwards compatability.\n\tDiffModeNotNormalized                      // Diff objects are considered to be in not normalized state.\n\tDiffModeNormalized                         // Diff objects are considered to be in normalized state.\n\tDiffModeSkipInvalid                        // Invalid changes are skipped, instead of returning an error.\n)\n\n// Is reports whether c is match the given change kind.\nfunc (k ChangeKind) Is(c ChangeKind) bool {\n\treturn k == c || k&c != 0\n}\n\ntype (\n\t// Differ is the interface implemented by the different\n\t// drivers for comparing and diffing schema top elements.\n\tDiffer interface {\n\t\t// RealmDiff returns a diff report for migrating a realm\n\t\t// (or a database) from state \"from\" to state \"to\". An error\n\t\t// is returned if such step is not possible.\n\t\tRealmDiff(from, to *Realm, opts ...DiffOption) ([]Change, error)\n\n\t\t// SchemaDiff returns a diff report for migrating a schema\n\t\t// from state \"from\" to state \"to\". An error is returned\n\t\t// if such step is not possible.\n\t\tSchemaDiff(from, to *Schema, opts ...DiffOption) ([]Change, error)\n\n\t\t// TableDiff returns a diff report for migrating a table\n\t\t// from state \"from\" to state \"to\". An error is returned\n\t\t// if such step is not possible.\n\t\tTableDiff(from, to *Table, opts ...DiffOption) ([]Change, error)\n\t}\n\n\t// DiffMode defines the diffing mode, e.g. if objects are normalized or not.\n\tDiffMode uint8\n\n\t// DiffOptions defines the standard and per-driver configuration\n\t// for the schema diffing process.\n\tDiffOptions struct {\n\t\t// SkipChanges defines a list of change types to skip.\n\t\tSkipChanges []Change\n\n\t\t// DiffMode defines the diffing mode.\n\t\tMode DiffMode\n\n\t\t// Extra defines per-driver configuration. If not\n\t\t// nil, should be set to schemahcl.Extension.\n\t\tExtra any // avoid circular dependency with schemahcl.\n\n\t\t// AskFunc can be implemented by the caller to\n\t\t// make diff process interactive.\n\t\tAskFunc func(string, []string) (string, error)\n\t}\n\n\t// DiffOption allows configuring the DiffOptions using functional options.\n\tDiffOption func(*DiffOptions)\n)\n\n// Is reports whether m is match the given mode.\nfunc (m DiffMode) Is(m1 DiffMode) bool {\n\treturn m == m1 || m&m1 != 0\n}\n\n// NewDiffOptions creates a new DiffOptions from the given configuration.\nfunc NewDiffOptions(opts ...DiffOption) *DiffOptions {\n\to := &DiffOptions{}\n\tfor _, opt := range opts {\n\t\topt(o)\n\t}\n\treturn o\n}\n\n// DiffSkipChanges returns a DiffOption that skips the given change types.\n// For example, in order to skip all destructive changes, use:\n//\n//\tDiffSkipChanges(&DropSchema{}, &DropTable{}, &DropColumn{}, &DropIndex{}, &DropForeignKey{})\nfunc DiffSkipChanges(changes ...Change) DiffOption {\n\treturn func(o *DiffOptions) {\n\t\to.SkipChanges = append(o.SkipChanges, changes...)\n\t}\n}\n\n// DiffNormalized returns a DiffOption that sets DiffMode to DiffModeNormalized,\n// indicating the Differ should consider input objects as normalized, For example:\n//\n//\tDiffNormalized()\nfunc DiffNormalized() DiffOption {\n\treturn func(o *DiffOptions) {\n\t\to.Mode = DiffModeNormalized\n\t}\n}\n\n// Skipped reports whether the given change should be skipped.\nfunc (o *DiffOptions) Skipped(c Change) bool {\n\tfor _, s := range o.SkipChanges {\n\t\tif reflect.TypeOf(c) == reflect.TypeOf(s) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// AddOrSkip adds the given change to the list of changes if it is not skipped.\nfunc (o *DiffOptions) AddOrSkip(changes Changes, cs ...Change) Changes {\n\tfor _, c := range cs {\n\t\tif !o.Skipped(c) {\n\t\t\tchanges = append(changes, c)\n\t\t}\n\t}\n\treturn changes\n\n}\n\n// ErrLocked is returned on Lock calls which have failed to obtain the lock.\nvar ErrLocked = errors.New(\"sql/schema: lock is held by other session\")\n\ntype (\n\t// UnlockFunc is returned by the Locker to explicitly\n\t// release the named \"advisory lock\".\n\tUnlockFunc func() error\n\n\t// Locker is an interface that is optionally implemented by the different drivers\n\t// for obtaining an \"advisory lock\" with the given name.\n\tLocker interface {\n\t\t// Lock acquires a named \"advisory lock\", using the given timeout. Negative value means no timeout,\n\t\t// and the zero value means a \"try lock\" mode. i.e. return immediately if the lock is already taken.\n\t\t// The returned unlock function is used to release the advisory lock acquired by the session.\n\t\t//\n\t\t// An ErrLocked is returned if the operation failed to obtain the lock in all different timeout modes.\n\t\tLock(ctx context.Context, name string, timeout time.Duration) (UnlockFunc, error)\n\t}\n)\n\ntype (\n\t// Changes is a list of changes allow for searching and mutating changes.\n\tChanges []Change\n\n\t// ChangeDepender wraps the ChangeDeps method, which returns a dependency map\n\t// from each change to its dependent changes. This interface can optionally\n\t// be implemented by drivers.\n\tChangeDepender interface {\n\t\tChangeDeps([]Change) map[Change][]Change\n\t}\n)\n\n// IndexAddTable returns the index of the first AddTable in the changes\n// with the given name, or -1 if there is no such change in the Changes.\nfunc (c Changes) IndexAddTable(name string) int {\n\treturn c.search(func(c Change) bool {\n\t\ta, ok := c.(*AddTable)\n\t\treturn ok && a.T.Name == name\n\t})\n}\n\n// IndexDropTable returns the index of the first DropTable in the changes\n// with the given name, or -1 if there is no such change in the Changes.\nfunc (c Changes) IndexDropTable(name string) int {\n\treturn c.search(func(c Change) bool {\n\t\ta, ok := c.(*DropTable)\n\t\treturn ok && a.T.Name == name\n\t})\n}\n\n// LastIndexAddTable returns the index of the last AddTable in the changes\n// with the given name, or -1 if there is no such change in the Changes.\nfunc (c Changes) LastIndexAddTable(name string) int {\n\treturn c.rsearch(func(c Change) bool {\n\t\ta, ok := c.(*AddTable)\n\t\treturn ok && a.T.Name == name\n\t})\n}\n\n// LastIndexDropTable returns the index of the last DropTable in the changes\n// with the given name, or -1 if there is no such change in the Changes.\nfunc (c Changes) LastIndexDropTable(name string) int {\n\treturn c.rsearch(func(c Change) bool {\n\t\ta, ok := c.(*DropTable)\n\t\treturn ok && a.T.Name == name\n\t})\n}\n\n// IndexAddColumn returns the index of the first AddColumn in the changes\n// with the given name, or -1 if there is no such change in the Changes.\nfunc (c Changes) IndexAddColumn(name string) int {\n\treturn c.search(func(c Change) bool {\n\t\ta, ok := c.(*AddColumn)\n\t\treturn ok && a.C.Name == name\n\t})\n}\n\n// IndexDropColumn returns the index of the first DropColumn in the changes\n// with the given name, or -1 if there is no such change in the Changes.\nfunc (c Changes) IndexDropColumn(name string) int {\n\treturn c.search(func(c Change) bool {\n\t\td, ok := c.(*DropColumn)\n\t\treturn ok && d.C.Name == name\n\t})\n}\n\n// IndexModifyColumn returns the index of the first ModifyColumn in the changes\n// with the given name, or -1 if there is no such change in the Changes.\nfunc (c Changes) IndexModifyColumn(name string) int {\n\treturn c.search(func(c Change) bool {\n\t\ta, ok := c.(*ModifyColumn)\n\t\treturn ok && a.From.Name == name\n\t})\n}\n\n// IndexAddIndex returns the index of the first AddIndex in the changes\n// with the given name, or -1 if there is no such change in the Changes.\nfunc (c Changes) IndexAddIndex(name string) int {\n\treturn c.search(func(c Change) bool {\n\t\ta, ok := c.(*AddIndex)\n\t\treturn ok && a.I.Name == name\n\t})\n}\n\n// IndexDropIndex returns the index of the first DropIndex in the changes\n// with the given name, or -1 if there is no such change in the Changes.\nfunc (c Changes) IndexDropIndex(name string) int {\n\treturn c.search(func(c Change) bool {\n\t\ta, ok := c.(*DropIndex)\n\t\treturn ok && a.I.Name == name\n\t})\n}\n\n// RemoveIndex removes elements in the given indexes from the Changes.\nfunc (c *Changes) RemoveIndex(indexes ...int) {\n\tchanges := make([]Change, 0, len(*c)-len(indexes))\nLoop:\n\tfor i := range *c {\n\t\tfor _, idx := range indexes {\n\t\t\tif i == idx {\n\t\t\t\tcontinue Loop\n\t\t\t}\n\t\t}\n\t\tchanges = append(changes, (*c)[i])\n\t}\n\t*c = changes\n}\n\n// search returns the index of the first call to f that returns true, or -1.\nfunc (c Changes) search(f func(Change) bool) int {\n\tfor i := range c {\n\t\tif f(c[i]) {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// rsearch is the reversed version of search. It returns the\n// index of the last call to f that returns true, or -1.\nfunc (c Changes) rsearch(f func(Change) bool) int {\n\tfor i := len(c) - 1; i >= 0; i-- {\n\t\tif f(c[i]) {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// changes.\nfunc (*AddAttr) change()          {}\nfunc (*DropAttr) change()         {}\nfunc (*ModifyAttr) change()       {}\nfunc (*AddSchema) change()        {}\nfunc (*DropSchema) change()       {}\nfunc (*ModifySchema) change()     {}\nfunc (*AddTable) change()         {}\nfunc (*DropTable) change()        {}\nfunc (*ModifyTable) change()      {}\nfunc (*RenameTable) change()      {}\nfunc (*AddView) change()          {}\nfunc (*DropView) change()         {}\nfunc (*ModifyView) change()       {}\nfunc (*RenameView) change()       {}\nfunc (*AddFunc) change()          {}\nfunc (*DropFunc) change()         {}\nfunc (*ModifyFunc) change()       {}\nfunc (*RenameFunc) change()       {}\nfunc (*AddProc) change()          {}\nfunc (*DropProc) change()         {}\nfunc (*ModifyProc) change()       {}\nfunc (*RenameProc) change()       {}\nfunc (*AddObject) change()        {}\nfunc (*DropObject) change()       {}\nfunc (*ModifyObject) change()     {}\nfunc (*RenameObject) change()     {}\nfunc (*AddTrigger) change()       {}\nfunc (*DropTrigger) change()      {}\nfunc (*ModifyTrigger) change()    {}\nfunc (*RenameTrigger) change()    {}\nfunc (*AddIndex) change()         {}\nfunc (*DropIndex) change()        {}\nfunc (*ModifyIndex) change()      {}\nfunc (*RenameIndex) change()      {}\nfunc (*AddPrimaryKey) change()    {}\nfunc (*DropPrimaryKey) change()   {}\nfunc (*ModifyPrimaryKey) change() {}\nfunc (*AddCheck) change()         {}\nfunc (*DropCheck) change()        {}\nfunc (*ModifyCheck) change()      {}\nfunc (*AddColumn) change()        {}\nfunc (*DropColumn) change()       {}\nfunc (*ModifyColumn) change()     {}\nfunc (*RenameColumn) change()     {}\nfunc (*AddForeignKey) change()    {}\nfunc (*DropForeignKey) change()   {}\nfunc (*ModifyForeignKey) change() {}\nfunc (*RenameConstraint) change() {}\n\n// clauses.\nfunc (*IfExists) clause()    {}\nfunc (*IfNotExists) clause() {}\n"
  },
  {
    "path": "sql/schema/migrate_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schema_test\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestChanges_IndexAddTable(t *testing.T) {\n\tchanges := schema.Changes{\n\t\t&schema.AddTable{T: schema.NewTable(\"users\")},\n\t\t&schema.DropTable{T: schema.NewTable(\"posts\")},\n\t\t&schema.AddTable{T: schema.NewTable(\"posts\")},\n\t\t&schema.AddTable{T: schema.NewTable(\"posts\")},\n\t}\n\trequire.Equal(t, 2, changes.IndexAddTable(\"posts\"))\n\trequire.Equal(t, -1, changes.IndexAddTable(\"post_tags\"))\n}\n\nfunc TestChanges_IndexDropTable(t *testing.T) {\n\tchanges := schema.Changes{\n\t\t&schema.DropTable{T: schema.NewTable(\"users\")},\n\t\t&schema.AddTable{T: schema.NewTable(\"posts\")},\n\t\t&schema.DropTable{T: schema.NewTable(\"posts\")},\n\t}\n\trequire.Equal(t, 2, changes.IndexDropTable(\"posts\"))\n\trequire.Equal(t, -1, changes.IndexDropTable(\"post_tags\"))\n}\n\nfunc TestChanges_IndexAddColumn(t *testing.T) {\n\tchanges := schema.Changes{\n\t\t&schema.AddColumn{C: schema.NewColumn(\"name\")},\n\t\t&schema.DropColumn{C: schema.NewColumn(\"name\")},\n\t\t&schema.AddColumn{C: schema.NewColumn(\"name\")},\n\t}\n\trequire.Equal(t, 0, changes.IndexAddColumn(\"name\"))\n\trequire.Equal(t, -1, changes.IndexAddColumn(\"created_at\"))\n}\n\nfunc TestChanges_IndexDropColumn(t *testing.T) {\n\tchanges := schema.Changes{\n\t\t&schema.AddColumn{C: schema.NewColumn(\"name\")},\n\t\t&schema.DropColumn{C: schema.NewColumn(\"name\")},\n\t\t&schema.AddColumn{C: schema.NewColumn(\"name\")},\n\t}\n\trequire.Equal(t, 1, changes.IndexDropColumn(\"name\"))\n\trequire.Equal(t, -1, changes.IndexDropColumn(\"created_at\"))\n}\n\nfunc TestChanges_IndexAddIndex(t *testing.T) {\n\tchanges := schema.Changes{\n\t\t&schema.DropIndex{I: schema.NewIndex(\"name\")},\n\t\t&schema.AddIndex{I: schema.NewIndex(\"created_at\")},\n\t\t&schema.AddIndex{I: schema.NewIndex(\"name\")},\n\t}\n\trequire.Equal(t, 2, changes.IndexAddIndex(\"name\"))\n\trequire.Equal(t, -1, changes.IndexAddIndex(\"age\"))\n}\n\nfunc TestChanges_IndexDropIndex(t *testing.T) {\n\tchanges := schema.Changes{\n\t\t&schema.AddIndex{I: schema.NewIndex(\"name\")},\n\t\t&schema.DropIndex{I: schema.NewIndex(\"created_at\")},\n\t\t&schema.DropIndex{I: schema.NewIndex(\"name\")},\n\t}\n\trequire.Equal(t, 2, changes.IndexDropIndex(\"name\"))\n\trequire.Equal(t, -1, changes.IndexDropIndex(\"age\"))\n}\n\nfunc TestChanges_RemoveIndex(t *testing.T) {\n\tchanges := make(schema.Changes, 0, 5)\n\tfor i := 0; i < 5; i++ {\n\t\tchanges = append(changes, &schema.AddColumn{C: schema.NewColumn(strconv.Itoa(i))})\n\t}\n\tchanges.RemoveIndex(0)\n\trequire.Equal(t, 4, len(changes))\n\tfor i := 0; i < 4; i++ {\n\t\trequire.Equal(t, strconv.Itoa(i+1), changes[i].(*schema.AddColumn).C.Name)\n\t}\n\tchanges.RemoveIndex(0, 3, 2)\n\trequire.Equal(t, 1, len(changes))\n\trequire.Equal(t, \"2\", changes[0].(*schema.AddColumn).C.Name)\n}\n\nfunc ExampleChanges_RemoveIndex() {\n\tchanges := schema.Changes{\n\t\t&schema.AddIndex{I: schema.NewIndex(\"id\")},\n\t\t&schema.AddColumn{C: schema.NewColumn(\"new_name\")},\n\t\t&schema.AddColumn{C: schema.NewColumn(\"id\")},\n\t\t&schema.AddColumn{C: schema.NewColumn(\"created_at\")},\n\t\t&schema.DropColumn{C: schema.NewColumn(\"old_name\")},\n\t}\n\ti, j := changes.IndexAddColumn(\"new_name\"), changes.IndexDropColumn(\"old_name\")\n\tif i == -1 || j == -1 {\n\t\tlog.Fatalln(\"Unexpected change positions\")\n\t}\n\t// Replace \"add\" and \"drop\" with \"rename\".\n\tchanges = append(changes, &schema.RenameColumn{From: changes[j].(*schema.DropColumn).C, To: changes[i].(*schema.AddColumn).C})\n\tchanges.RemoveIndex(i, j)\n\tfor _, c := range changes {\n\t\tswitch c := c.(type) {\n\t\tcase *schema.AddColumn:\n\t\t\tfmt.Printf(\"%T(%s)\\n\", c, c.C.Name)\n\t\tcase *schema.DropColumn:\n\t\t\tfmt.Printf(\"%T(%s)\\n\", c, c.C.Name)\n\t\tcase *schema.RenameColumn:\n\t\t\tfmt.Printf(\"%T(%s -> %s)\\n\", c, c.From.Name, c.To.Name)\n\t\tcase *schema.AddIndex:\n\t\t\tfmt.Printf(\"%T(%s)\\n\", c, c.I.Name)\n\t\t}\n\t}\n\t// Output:\n\t// *schema.AddIndex(id)\n\t// *schema.AddColumn(id)\n\t// *schema.AddColumn(created_at)\n\t// *schema.RenameColumn(old_name -> new_name)\n}\n"
  },
  {
    "path": "sql/schema/schema.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage schema\n\nimport (\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype (\n\t// A Realm or a database describes a domain of schema resources that are logically connected\n\t// and can be accessed and queried in the same connection (e.g. a physical database instance).\n\tRealm struct {\n\t\tSchemas []*Schema\n\t\tAttrs   []Attr\n\t\tObjects []Object // Realm-level objects (e.g., users or extensions).\n\t}\n\n\t// A Schema describes a database schema (i.e. named database).\n\tSchema struct {\n\t\tName    string\n\t\tRealm   *Realm\n\t\tTables  []*Table\n\t\tViews   []*View\n\t\tFuncs   []*Func\n\t\tProcs   []*Proc\n\t\tAttrs   []Attr   // Attrs and options.\n\t\tObjects []Object // Schema-level objects (e.g., types or sequences).\n\t}\n\n\t// An Object represents a generic database object.\n\t// Note that this interface is implemented by some top-level types\n\t// to describe their relationship, and by driver specific types.\n\tObject interface {\n\t\tobj()\n\t}\n\n\t// A Table represents a table definition.\n\tTable struct {\n\t\tName        string\n\t\tSchema      *Schema\n\t\tColumns     []*Column\n\t\tIndexes     []*Index\n\t\tPrimaryKey  *Index\n\t\tForeignKeys []*ForeignKey\n\t\tAttrs       []Attr     // Attrs, constraints and options.\n\t\tTriggers    []*Trigger // Triggers on the table.\n\t\tDeps        []Object   // Objects this table depends on.\n\t\tRefs        []Object   // Objects that depends on this table.\n\t}\n\n\t// A View represents a view definition.\n\tView struct {\n\t\tName     string\n\t\tDef      string\n\t\tSchema   *Schema\n\t\tColumns  []*Column\n\t\tAttrs    []Attr     // Attrs and options.\n\t\tIndexes  []*Index   // Indexes on materialized view.\n\t\tTriggers []*Trigger // Triggers on the view.\n\t\tDeps     []Object   // Objects this view depends on.\n\t\tRefs     []Object   // Objects that depends on this view.\n\t}\n\n\t// A Column represents a column definition.\n\tColumn struct {\n\t\tName    string\n\t\tType    *ColumnType\n\t\tDefault Expr\n\t\tAttrs   []Attr\n\t\tIndexes []*Index\n\t\t// Foreign keys that this column is\n\t\t// part of their child columns.\n\t\tForeignKeys []*ForeignKey\n\t}\n\t// NamedDefault defines a named default expression.\n\tNamedDefault struct {\n\t\tExpr\n\t\tName  string\n\t\tAttrs []Attr\n\t}\n\t// ColumnType represents a column type that is implemented by the dialect.\n\tColumnType struct {\n\t\tType Type\n\t\tRaw  string\n\t\tNull bool\n\t}\n\n\t// An Index represents an index definition.\n\tIndex struct {\n\t\tName   string\n\t\tUnique bool\n\t\t// Table or View that this index belongs to.\n\t\tTable *Table\n\t\tView  *View\n\t\tAttrs []Attr\n\t\tParts []*IndexPart\n\t}\n\n\t// An IndexPart represents an index part that\n\t// can be either an expression or a column.\n\tIndexPart struct {\n\t\t// SeqNo represents the sequence number of the key part\n\t\t// in the index.\n\t\tSeqNo int\n\t\t// Desc indicates if the key part is stored in descending\n\t\t// order. All databases use ascending order as default.\n\t\tDesc  bool\n\t\tX     Expr\n\t\tC     *Column\n\t\tAttrs []Attr\n\t}\n\n\t// A ForeignKey represents an index definition.\n\tForeignKey struct {\n\t\tSymbol     string // Constraint name, if exists.\n\t\tTable      *Table\n\t\tColumns    []*Column\n\t\tRefTable   *Table\n\t\tRefColumns []*Column\n\t\tOnUpdate   ReferenceOption\n\t\tOnDelete   ReferenceOption\n\t\tAttrs      []Attr\n\t}\n\n\t// A Trigger represents a trigger definition.\n\tTrigger struct {\n\t\tName string\n\t\t// Table or View that this trigger belongs to.\n\t\tTable      *Table\n\t\tView       *View\n\t\tActionTime TriggerTime    // BEFORE, AFTER, or INSTEAD OF.\n\t\tEvents     []TriggerEvent // INSERT, UPDATE, DELETE, etc.\n\t\tFor        TriggerFor     // FOR EACH ROW or FOR EACH STATEMENT.\n\t\tBody       string         // Trigger body only.\n\t\tAttrs      []Attr         // WHEN, REFERENCING, etc.\n\t\tDeps       []Object       // Objects this trigger depends on.\n\t\tRefs       []Object       // Objects that depend on this trigger.\n\t}\n\n\t// TriggerTime represents the trigger action time.\n\tTriggerTime string\n\n\t// TriggerFor represents the trigger FOR EACH spec.\n\tTriggerFor string\n\n\t// TriggerEvent represents the trigger event.\n\tTriggerEvent struct {\n\t\tName    string    // Name of the event (e.g. INSERT, UPDATE, DELETE).\n\t\tColumns []*Column // Columns that might be associated with the event.\n\t}\n\n\t// Func represents a function definition.\n\tFunc struct {\n\t\tName   string\n\t\tSchema *Schema\n\t\tArgs   []*FuncArg\n\t\tRet    Type\n\t\tBody   string   // Function body only.\n\t\tLang   string   // Language (e.g. SQL, PL/pgSQL, etc.).\n\t\tAttrs  []Attr   // Extra driver specific attributes.\n\t\tDeps   []Object // Objects this function depends on.\n\t\tRefs   []Object // Objects that depend on this function.\n\t}\n\n\t// Proc represents a procedure definition.\n\tProc struct {\n\t\tName   string\n\t\tSchema *Schema\n\t\tArgs   []*FuncArg\n\t\tBody   string   // Function body only.\n\t\tLang   string   // Language (e.g. SQL, PL/pgSQL, etc.).\n\t\tAttrs  []Attr   // Extra driver specific attributes.\n\t\tDeps   []Object // Objects this function depends on.\n\t\tRefs   []Object // Objects that depend on this Proc.\n\t}\n\n\t// A FuncArg represents a single function argument.\n\tFuncArg struct {\n\t\tName    string      // Optional name.\n\t\tType    Type        // Argument type.\n\t\tDefault Expr        // Default value.\n\t\tMode    FuncArgMode // Argument mode.\n\t\tAttrs   []Attr      // Extra driver specific attributes.\n\t}\n\n\t// FuncArgMode represents a function argument mode.\n\tFuncArgMode string\n)\n\n// List of supported function argument modes.\nconst (\n\tFuncArgModeIn       FuncArgMode = \"IN\"\n\tFuncArgModeOut      FuncArgMode = \"OUT\"\n\tFuncArgModeInOut    FuncArgMode = \"INOUT\"\n\tFuncArgModeVariadic FuncArgMode = \"VARIADIC\"\n)\n\n// List of supported trigger action times.\nconst (\n\tTriggerTimeBefore  TriggerTime = \"BEFORE\"\n\tTriggerTimeAfter   TriggerTime = \"AFTER\"\n\tTriggerTimeInstead TriggerTime = \"INSTEAD OF\"\n)\n\n// List of supported trigger FOR EACH spec.\nconst (\n\tTriggerForRow  TriggerFor = \"ROW\"\n\tTriggerForStmt TriggerFor = \"STATEMENT\"\n)\n\n// List of supported trigger events.\nvar (\n\tTriggerEventInsert   = TriggerEvent{Name: \"INSERT\"}\n\tTriggerEventUpdate   = TriggerEvent{Name: \"UPDATE\"}\n\tTriggerEventDelete   = TriggerEvent{Name: \"DELETE\"}\n\tTriggerEventTruncate = TriggerEvent{Name: \"TRUNCATE\"}\n)\n\n// TriggerEventUpdateOf returns an UPDATE OF trigger event.\nfunc TriggerEventUpdateOf(columns ...*Column) TriggerEvent {\n\treturn TriggerEvent{Name: \"UPDATE OF\", Columns: columns}\n}\n\n// Schema returns the first schema that matched the given name.\nfunc (r *Realm) Schema(name string) (*Schema, bool) {\n\tfor _, s := range r.Schemas {\n\t\tif s.Name == name {\n\t\t\treturn s, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Object returns the first object that matched the given predicate.\nfunc (r *Realm) Object(f func(Object) bool) (Object, bool) {\n\tfor _, o := range r.Objects {\n\t\tif f(o) {\n\t\t\treturn o, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// PosSetter wraps the two methods for getting\n// and setting positions for schema objects.\ntype PosSetter interface {\n\tPos() *Pos\n\tSetPos(*Pos)\n}\n\n// Pos of the schema, if exists.\nfunc (s *Schema) Pos() *Pos {\n\tfor _, a := range s.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Pos of the enum, if exists.\nfunc (e *EnumType) Pos() *Pos {\n\tfor _, a := range e.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Table returns the first table that matched the given name.\nfunc (s *Schema) Table(name string) (*Table, bool) {\n\tfor _, t := range s.Tables {\n\t\tif t.Name == name {\n\t\t\treturn t, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// View returns the first view that matched the given name.\nfunc (s *Schema) View(name string) (*View, bool) {\n\tfor _, v := range s.Views {\n\t\tif v.Name == name && !v.Materialized() {\n\t\t\treturn v, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Materialized returns the first materialized view that matched the given name.\nfunc (s *Schema) Materialized(name string) (*View, bool) {\n\tfor _, v := range s.Views {\n\t\tif v.Name == name && v.Materialized() {\n\t\t\treturn v, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Func returns the first function that matched the given name.\nfunc (s *Schema) Func(name string) (*Func, bool) {\n\tfor _, f := range s.Funcs {\n\t\tif f.Name == name {\n\t\t\treturn f, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Proc returns the first procedure that matched the given name.\nfunc (s *Schema) Proc(name string) (*Proc, bool) {\n\tfor _, p := range s.Procs {\n\t\tif p.Name == name {\n\t\t\treturn p, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Object returns the first object that matched the given predicate.\nfunc (s *Schema) Object(f func(Object) bool) (Object, bool) {\n\tfor _, o := range s.Objects {\n\t\tif f(o) {\n\t\t\treturn o, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Column returns the first column that matched the given name.\nfunc (t *Table) Column(name string) (*Column, bool) {\n\tfor _, c := range t.Columns {\n\t\tif c.Name == name {\n\t\t\treturn c, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Pos of the table, if exists.\nfunc (t *Table) Pos() *Pos {\n\tfor _, a := range t.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Index returns the first index that matched the given name.\nfunc (t *Table) Index(name string) (*Index, bool) {\n\tfor _, i := range t.Indexes {\n\t\tif i.Name == name {\n\t\t\treturn i, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// ForeignKey returns the first foreign-key that matched the given symbol (constraint name).\nfunc (t *Table) ForeignKey(symbol string) (*ForeignKey, bool) {\n\tfor _, f := range t.ForeignKeys {\n\t\tif f.Symbol == symbol {\n\t\t\treturn f, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Trigger returns the first trigger that matches the given name.\nfunc (t *Table) Trigger(name string) (*Trigger, bool) {\n\tfor _, r := range t.Triggers {\n\t\tif r.Name == name {\n\t\t\treturn r, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Checks of the table.\nfunc (t *Table) Checks() (ck []*Check) {\n\tfor _, a := range t.Attrs {\n\t\tif c, ok := a.(*Check); ok {\n\t\t\tck = append(ck, c)\n\t\t}\n\t}\n\treturn ck\n}\n\n// Pos of the view, if exists.\nfunc (v *View) Pos() *Pos {\n\tfor _, a := range v.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Materialized reports if the view is materialized.\nfunc (v *View) Materialized() bool {\n\tfor _, a := range v.Attrs {\n\t\tif _, ok := a.(*Materialized); ok {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// SetMaterialized reports if the view is materialized.\nfunc (v *View) SetMaterialized(b bool) *View {\n\tif b {\n\t\tReplaceOrAppend(&v.Attrs, &Materialized{})\n\t} else {\n\t\tv.Attrs = RemoveAttr[*Materialized](v.Attrs)\n\t}\n\treturn v\n}\n\n// Column returns the first column that matched the given name.\nfunc (v *View) Column(name string) (*Column, bool) {\n\tfor _, c := range v.Columns {\n\t\tif c.Name == name {\n\t\t\treturn c, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Index returns the first index that matched the given name.\nfunc (v *View) Index(name string) (*Index, bool) {\n\tfor _, i := range v.Indexes {\n\t\tif i.Name == name {\n\t\t\treturn i, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// Trigger returns the first trigger that matches the given name.\nfunc (v *View) Trigger(name string) (*Trigger, bool) {\n\tfor _, r := range v.Triggers {\n\t\tif r.Name == name {\n\t\t\treturn r, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// AsTable returns a table that represents the view.\nfunc (v *View) AsTable() *Table {\n\treturn NewTable(v.Name).\n\t\tSetSchema(v.Schema).\n\t\tAddColumns(v.Columns...)\n}\n\n// SetPos sets the position of the function.\nfunc (f *Func) SetPos(p *Pos) {\n\tReplaceOrAppend(&f.Attrs, p)\n}\n\n// Pos of the schema, if exists.\nfunc (f *Func) Pos() *Pos {\n\tfor _, a := range f.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// SetPos sets the position of the schema.\nfunc (s *Schema) SetPos(p *Pos) {\n\tReplaceOrAppend(&s.Attrs, p)\n}\n\n// SetPos sets the position of the enum type.\nfunc (e *EnumType) SetPos(p *Pos) {\n\tReplaceOrAppend(&e.Attrs, p)\n}\n\n// SetPos sets the position of the table.\nfunc (t *Table) SetPos(p *Pos) {\n\tReplaceOrAppend(&t.Attrs, p)\n}\n\n// SetPos sets the position of the view.\nfunc (v *View) SetPos(p *Pos) {\n\tReplaceOrAppend(&v.Attrs, p)\n}\n\n// SetPos sets the position of the column.\nfunc (c *Column) SetPos(p *Pos) {\n\tReplaceOrAppend(&c.Attrs, p)\n}\n\n// SetPos sets the position of the check.\nfunc (c *Check) SetPos(p *Pos) {\n\tReplaceOrAppend(&c.Attrs, p)\n}\n\n// SetPos sets the position of the index.\nfunc (i *Index) SetPos(p *Pos) {\n\tReplaceOrAppend(&i.Attrs, p)\n}\n\n// SetPos sets the position of the index part.\nfunc (p *IndexPart) SetPos(p1 *Pos) {\n\tReplaceOrAppend(&p.Attrs, p1)\n}\n\n// SetPos sets the position of the foreign key.\nfunc (f *ForeignKey) SetPos(p *Pos) {\n\tReplaceOrAppend(&f.Attrs, p)\n}\n\n// SetPos sets the position of the procedure.\nfunc (p *Proc) SetPos(p1 *Pos) {\n\tReplaceOrAppend(&p.Attrs, p1)\n}\n\n// Pos of the schema, if exists.\nfunc (p *Proc) Pos() *Pos {\n\tfor _, a := range p.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Pos of the column, if exists.\nfunc (c *Column) Pos() *Pos {\n\tfor _, a := range c.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Pos of the index, if exists.\nfunc (i *Index) Pos() *Pos {\n\tfor _, a := range i.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Pos of the index part, if exists.\nfunc (p *IndexPart) Pos() *Pos {\n\tfor _, a := range p.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Pos of the check, if exists.\nfunc (c *Check) Pos() *Pos {\n\tfor _, a := range c.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Pos of the foreign-key, if exists.\nfunc (f *ForeignKey) Pos() *Pos {\n\tfor _, a := range f.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// Column returns the first column that matches the given name.\nfunc (f *ForeignKey) Column(name string) (*Column, bool) {\n\tfor _, c := range f.Columns {\n\t\tif c.Name == name {\n\t\t\treturn c, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// RefColumn returns the first referenced column that matches the given name.\nfunc (f *ForeignKey) RefColumn(name string) (*Column, bool) {\n\tfor _, c := range f.RefColumns {\n\t\tif c.Name == name {\n\t\t\treturn c, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\n// SetPos sets the position of the trigger.\nfunc (t *Trigger) SetPos(p *Pos) {\n\tReplaceOrAppend(&t.Attrs, p)\n}\n\n// Pos of the schema, if exists.\nfunc (t *Trigger) Pos() *Pos {\n\tfor _, a := range t.Attrs {\n\t\tif p, ok := a.(*Pos); ok {\n\t\t\treturn p\n\t\t}\n\t}\n\treturn nil\n}\n\n// ReferenceOption for constraint actions.\ntype ReferenceOption string\n\n// Reference options (actions) specified by ON UPDATE and ON DELETE\n// subclauses of the FOREIGN KEY clause.\nconst (\n\tNoAction   ReferenceOption = \"NO ACTION\"\n\tRestrict   ReferenceOption = \"RESTRICT\"\n\tCascade    ReferenceOption = \"CASCADE\"\n\tSetNull    ReferenceOption = \"SET NULL\"\n\tSetDefault ReferenceOption = \"SET DEFAULT\"\n)\n\ntype (\n\t// A Type represents a database type. The types below implements this\n\t// interface and can be used for describing schemas.\n\t//\n\t// The Type interface can also be implemented outside this package as follows:\n\t//\n\t//\ttype SpatialType struct {\n\t//\t\tschema.Type\n\t//\t\tT string\n\t//\t}\n\t//\n\t//\tvar t schema.Type = &SpatialType{T: \"point\"}\n\t//\n\tType interface {\n\t\ttyp()\n\t}\n\n\t// EnumType represents an enum type.\n\tEnumType struct {\n\t\tT      string   // Optional type.\n\t\tValues []string // Enum values.\n\t\tSchema *Schema  // Optional schema.\n\t\tAttrs  []Attr   // Extra attributes.\n\t}\n\n\t// BinaryType represents a type that stores binary data.\n\tBinaryType struct {\n\t\tT    string\n\t\tSize *int\n\t}\n\n\t// StringType represents a string type.\n\tStringType struct {\n\t\tT     string\n\t\tSize  int\n\t\tAttrs []Attr\n\t}\n\n\t// BoolType represents a boolean type.\n\tBoolType struct {\n\t\tT string\n\t}\n\n\t// IntegerType represents an int type.\n\tIntegerType struct {\n\t\tT        string\n\t\tUnsigned bool\n\t\tAttrs    []Attr\n\t}\n\n\t// DecimalType represents a fixed-point type that stores exact numeric values.\n\tDecimalType struct {\n\t\tT         string\n\t\tPrecision int\n\t\tScale     int\n\t\tUnsigned  bool\n\t}\n\n\t// FloatType represents a floating-point type that stores approximate numeric values.\n\tFloatType struct {\n\t\tT         string\n\t\tUnsigned  bool\n\t\tPrecision int\n\t}\n\n\t// TimeType represents a date/time type.\n\tTimeType struct {\n\t\tT         string\n\t\tPrecision *int\n\t\tScale     *int\n\t\tAttrs     []Attr\n\t}\n\n\t// JSONType represents a JSON type.\n\tJSONType struct {\n\t\tT string\n\t}\n\n\t// SpatialType represents a spatial/geometric type.\n\tSpatialType struct {\n\t\tT string\n\t}\n\n\t// A UUIDType defines a UUID type.\n\tUUIDType struct {\n\t\tT string\n\t}\n\n\t// UnsupportedType represents a type that is not supported by the drivers.\n\tUnsupportedType struct {\n\t\tT string\n\t}\n\n\t// TypeParser is an interface that is required be implemented by\n\t// different drivers for parsing column types from their database\n\t// forms to the schema representation.\n\tTypeParser interface {\n\t\t// ParseType converts the raw database type to its schema.Type representation.\n\t\tParseType(string) (Type, error)\n\t}\n\n\t// TypeFormatter is an interface that is required to be implemented by\n\t// different drivers to format column types into their corresponding\n\t// database forms.\n\tTypeFormatter interface {\n\t\t// FormatType converts a schema type to its column form in the database.\n\t\tFormatType(Type) (string, error)\n\t}\n\n\t// TypeParseFormatter that groups the TypeParser and TypeFormatter interfaces.\n\tTypeParseFormatter interface {\n\t\tTypeParser\n\t\tTypeFormatter\n\t}\n)\n\ntype (\n\t// Expr defines an SQL expression in schema DDL.\n\t//\n\t// The Expr interface can also be implemented outside this package as follows:\n\t//\n\t// \ttype NamedDefault struct {\n\t// \t\tschema.Expr\n\t// \t\tName string\n\t// \t}\n\t// \t// Underlying returns the underlying expression.\n\t// \tfunc (e *NamedDefault) Underlying() schema.Expr { return e.Expr }\n\t//\n\t//  var e schema.Expr = &NamedDefault{Expr: &schema.Literal{V: \"bar\"}, Name: \"foo\"}\n\tExpr interface {\n\t\texpr()\n\t}\n\n\t// Literal represents a basic literal expression like 1, or '1'.\n\t// String literals are usually quoted with single or double quotes.\n\tLiteral struct {\n\t\tV string\n\t}\n\n\t// RawExpr represents a raw expression like \"uuid()\" or \"current_timestamp()\".\n\t// Unlike literals, raw expression are usually inlined as is on migration.\n\tRawExpr struct {\n\t\tX string\n\t}\n)\n\ntype (\n\t// Attr represents the interface that all attributes implement.\n\tAttr interface {\n\t\tattr()\n\t}\n\n\t// Comment describes a schema element comment.\n\tComment struct {\n\t\tText string\n\t}\n\n\t// Charset describes a column or a table character-set setting.\n\tCharset struct {\n\t\tV string\n\t}\n\n\t// Collation describes a column or a table collation setting.\n\tCollation struct {\n\t\tV string\n\t}\n\n\t// Check describes a CHECK constraint.\n\tCheck struct {\n\t\tName  string // Optional constraint name.\n\t\tExpr  string // Actual CHECK.\n\t\tAttrs []Attr // Additional attributes (e.g. ENFORCED).\n\t}\n\n\t// GeneratedExpr describes the expression used for generating\n\t// the value of a generated/virtual column.\n\tGeneratedExpr struct {\n\t\tExpr string\n\t\tType string // Optional type. e.g. STORED or VIRTUAL.\n\t}\n\n\t// ViewCheckOption describes the standard 'WITH CHECK OPTION clause' of a view.\n\tViewCheckOption struct {\n\t\tV string // LOCAL, CASCADED, NONE, or driver specific.\n\t}\n\n\t// Materialized is a schema attribute that attached to views to indicates\n\t// they are MATERIALIZED VIEWs.\n\tMaterialized struct {\n\t\tAttr\n\t}\n\n\t// Pos is an attribute that holds the position of a schema element.\n\tPos struct {\n\t\t// Filename is the name (or full path) of the file which loaded the schema element.\n\t\tFilename string\n\n\t\t// Start and End represent the bounds of this range.\n\t\tStart, End struct {\n\t\t\tLine, Column, Byte int // hcl.Pos fields.\n\t\t}\n\t}\n)\n\n// String returns the position in editor/LSP style.\n// Format: \"filename:line[:c][-end_line[:end_c]]\"\nfunc (p *Pos) String() string {\n\tif p == nil {\n\t\treturn \"\"\n\t}\n\tvar b strings.Builder\n\tif p.Filename != \"\" {\n\t\tb.WriteString(p.Filename)\n\t} else {\n\t\tb.WriteByte('-')\n\t}\n\tif p.Start.Line > 0 {\n\t\tb.WriteByte(':')\n\t\tb.WriteString(strconv.Itoa(p.Start.Line))\n\t\tif p.Start.Column > 0 {\n\t\t\tb.WriteByte(':')\n\t\t\tb.WriteString(strconv.Itoa(p.Start.Column))\n\t\t}\n\t}\n\treturn b.String()\n}\n\n// A list of known view check options.\nconst (\n\tViewCheckOptionNone     = \"NONE\"\n\tViewCheckOptionLocal    = \"LOCAL\"\n\tViewCheckOptionCascaded = \"CASCADED\"\n)\n\n// objects.\nfunc (*Table) obj()    {}\nfunc (*View) obj()     {}\nfunc (*Func) obj()     {}\nfunc (*Proc) obj()     {}\nfunc (*Trigger) obj()  {}\nfunc (*EnumType) obj() {}\n\n// constraints are objects.\nfunc (*Index) obj()        {}\nfunc (*Check) obj()        {}\nfunc (*ForeignKey) obj()   {}\nfunc (*NamedDefault) obj() {}\n\n// expressions.\nfunc (*Literal) expr() {}\nfunc (*RawExpr) expr() {}\n\n// types.\nfunc (*BoolType) typ()        {}\nfunc (*EnumType) typ()        {}\nfunc (*TimeType) typ()        {}\nfunc (*JSONType) typ()        {}\nfunc (*FloatType) typ()       {}\nfunc (*StringType) typ()      {}\nfunc (*BinaryType) typ()      {}\nfunc (*SpatialType) typ()     {}\nfunc (*UUIDType) typ()        {}\nfunc (*IntegerType) typ()     {}\nfunc (*DecimalType) typ()     {}\nfunc (*UnsupportedType) typ() {}\n\n// attributes.\nfunc (*Pos) attr()             {}\nfunc (*Check) attr()           {}\nfunc (*Comment) attr()         {}\nfunc (*Charset) attr()         {}\nfunc (*Collation) attr()       {}\nfunc (*GeneratedExpr) attr()   {}\nfunc (*ViewCheckOption) attr() {}\n\n// SpecType returns the type of the spec.\nfunc (e *EnumType) SpecType() string { return \"enum\" }\n\n// SpecName returns the name of the spec.\nfunc (e *EnumType) SpecName() string { return e.T }\n\n// Underlying returns underlying the expression.\nfunc (n *NamedDefault) Underlying() Expr {\n\treturn n.Expr\n}\n\n// UnderlyingExpr returns the underlying expression of x.\nfunc UnderlyingExpr(x Expr) Expr {\n\tif w, ok := x.(interface{ Underlying() Expr }); ok {\n\t\treturn UnderlyingExpr(w.Underlying())\n\t}\n\treturn x\n}\n\n// UnderlyingType returns the underlying type of t.\nfunc UnderlyingType(t Type) Type {\n\tif w, ok := t.(interface{ Underlying() Type }); ok {\n\t\treturn UnderlyingType(w.Underlying())\n\t}\n\treturn t\n}\n\n// IsType return true if somewhere in the type-chain of t1 is the same as t2.\nfunc IsType(t1, t2 Type) bool {\n\tif t1 == nil || t2 == nil {\n\t\treturn t1 == t2\n\t}\n\treturn sameType(t1, t2, reflect.TypeOf(t2).Comparable())\n}\n\nfunc sameType(t1, t2 Type, targetComparable bool) bool {\n\tfor {\n\t\tif targetComparable && t1 == t2 {\n\t\t\treturn true\n\t\t}\n\t\t// Check if t1 implements the Is method.\n\t\t// Then call it to check if it is the same as t2.\n\t\t// This is useful for comparing types that are\n\t\t// not directly the same pointer.\n\t\tif x, ok := t1.(interface{ Is(Type) bool }); ok && x.Is(t2) {\n\t\t\treturn true\n\t\t}\n\t\t// Check if t1 has an underlying type.\n\t\t// Then use it to compare with t2.\n\t\tif x, ok := t1.(interface{ Underlying() Type }); ok {\n\t\t\tif t1 = x.Underlying(); t1 != nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "sql/sqlcheck/condrop/condrop.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage condrop\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n)\n\n// Analyzer checks for constraint-dropping changes.\ntype Analyzer struct {\n\tsqlcheck.Options\n}\n\n// New creates a new constraint-dropping Analyzer with the given options.\nfunc New(r *schemahcl.Resource) (*Analyzer, error) {\n\taz := &Analyzer{}\n\tif r, ok := r.Resource(az.Name()); ok {\n\t\tif err := r.As(&az.Options); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sql/sqlcheck: parsing datadepend check options: %w\", err)\n\t\t}\n\t}\n\treturn az, nil\n}\n\n// List of codes.\nvar (\n\tcodeDropF = sqlcheck.Code(\"CD101\")\n)\n\n// Name of the analyzer. Implements the sqlcheck.NamedAnalyzer interface.\nfunc (*Analyzer) Name() string {\n\treturn \"condrop\"\n}\n\n// Analyze implements sqlcheck.Analyzer.\nfunc (a *Analyzer) Analyze(_ context.Context, p *sqlcheck.Pass) error {\n\tvar diags []sqlcheck.Diagnostic\n\tfor _, sc := range p.File.Changes {\n\t\tfor _, c := range sc.Changes {\n\t\t\tc, ok := c.(*schema.ModifyTable)\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor i := range c.Changes {\n\t\t\t\td, ok := c.Changes[i].(*schema.DropForeignKey)\n\t\t\t\tif !ok || p.File.ForeignKeySpan(c.T, d.F)&sqlcheck.SpanAdded != 0 {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tdropC := func() bool {\n\t\t\t\t\tfor i := range d.F.Columns {\n\t\t\t\t\t\tif schema.Changes(c.Changes).IndexDropColumn(d.F.Columns[i].Name) != -1 {\n\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn false\n\t\t\t\t}()\n\t\t\t\t// If none of the foreign-key columns were dropped.\n\t\t\t\tif !dropC {\n\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\tCode: codeDropF,\n\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\tText: fmt.Sprintf(\"Dropping foreign-key constraint %q\", d.F.Symbol),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif len(diags) > 0 {\n\t\tconst reportText = \"constraint deletion detected\"\n\t\tp.Reporter.WriteReport(sqlcheck.Report{Text: reportText, Diagnostics: diags})\n\t\tif sqlx.V(a.Error) {\n\t\t\treturn errors.New(reportText)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "sql/sqlcheck/condrop/condrop_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage condrop_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlcheck/condrop\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestAnalyzer_DropForeignKey(t *testing.T) {\n\tvar (\n\t\treport sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{Name: \"mysql\"},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `pets`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"pets\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t\t\t&schema.DropColumn{\n\t\t\t\t\t\t\t\t\t\tC: schema.NewColumn(\"c\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&schema.DropForeignKey{\n\t\t\t\t\t\t\t\t\t\tF: schema.NewForeignKey(\"owner_id\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"owner_id\")),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&schema.DropForeignKey{\n\t\t\t\t\t\t\t\t\t\tF: schema.NewForeignKey(\"c\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"c\"), schema.NewColumn(\"d\")),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := condrop.New(&schemahcl.Resource{})\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.NoError(t, err)\n\trequire.Len(t, report.Diagnostics, 1)\n\trequire.Equal(t, \"constraint deletion detected\", report.Text)\n\trequire.Equal(t, `Dropping foreign-key constraint \"owner_id\"`, report.Diagnostics[0].Text)\n}\n\ntype testFile struct {\n\tname string\n\tmigrate.File\n}\n\nfunc (t testFile) Name() string {\n\treturn t.name\n}\n"
  },
  {
    "path": "sql/sqlcheck/datadepend/datadepend.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage datadepend\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n)\n\ntype (\n\t// Analyzer checks data-dependent changes.\n\tAnalyzer struct {\n\t\tsqlcheck.Options\n\t\tHandler\n\t}\n\n\t// Handler holds the underlying driver handlers.\n\tHandler struct {\n\t\t// AddNotNull is applied when a new non-nullable column was\n\t\t// added to an existing table.\n\t\tAddNotNull ColumnHandler\n\n\t\t// ModifyNotNull is an optional handler applied when\n\t\t// a nullable column was changed to non-nullable.\n\t\tModifyNotNull ColumnHandler\n\t}\n\n\t// ColumnPass wraps the information needed\n\t// by the handler below to diagnose columns.\n\tColumnPass struct {\n\t\t*sqlcheck.Pass\n\t\tChange *sqlcheck.Change // Change context (statement).\n\t\tTable  *schema.Table    // The table this column belongs to.\n\t\tColumn *schema.Column   // The diagnosed column.\n\t}\n\n\t// ColumnHandler allows provide custom diagnostic for specific column rules.\n\tColumnHandler func(*ColumnPass) ([]sqlcheck.Diagnostic, error)\n)\n\n// New creates a new data-dependent analyzer with the given options.\nfunc New(r *schemahcl.Resource, h Handler) (*Analyzer, error) {\n\taz := &Analyzer{Handler: h}\n\tif r, ok := r.Resource(az.Name()); ok {\n\t\tif err := r.As(&az.Options); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sql/sqlcheck: parsing datadepend check options: %w\", err)\n\t\t}\n\t}\n\treturn az, nil\n}\n\n// Name of the analyzer. Implements the sqlcheck.NamedAnalyzer interface.\nfunc (*Analyzer) Name() string {\n\treturn \"data_depend\"\n}\n\n// Analyze runs data-depend analysis on MySQL changes.\nfunc (a *Analyzer) Analyze(ctx context.Context, p *sqlcheck.Pass) error {\n\treturn a.Report(p, a.Diagnostics(ctx, p))\n}\n\n// List of codes.\nvar (\n\tcodeAddUniqueI  = sqlcheck.Code(\"MF101\")\n\tcodeModUniqueI  = sqlcheck.Code(\"MF102\")\n\tcodeAddNotNullC = sqlcheck.Code(\"MF103\")\n\tcodeModNotNullC = sqlcheck.Code(\"MF104\")\n)\n\n// Diagnostics runs the common analysis on the file and returns its diagnostics.\nfunc (a *Analyzer) Diagnostics(_ context.Context, p *sqlcheck.Pass) (diags []sqlcheck.Diagnostic) {\n\tfor _, sc := range p.File.Changes {\n\t\tvar dropI []*schema.DropIndex\n\t\tfor _, sc := range p.File.Changes {\n\t\t\tfor _, c := range sc.Changes {\n\t\t\t\tm, ok := c.(*schema.ModifyTable)\n\t\t\t\tif !ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfor _, mc := range m.Changes {\n\t\t\t\t\tif d, ok := mc.(*schema.DropIndex); ok {\n\t\t\t\t\t\tdropI = append(dropI, d)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor _, c := range sc.Changes {\n\t\t\tm, ok := c.(*schema.ModifyTable)\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, c := range m.Changes {\n\t\t\t\tswitch c := c.(type) {\n\t\t\t\tcase *schema.AddIndex:\n\t\t\t\t\t// Check if the current index is not unique or if it matches any of the dropped unique indexes by comparing their parts.\n\t\t\t\t\tif !c.I.Unique || slices.ContainsFunc(dropI, func(drop *schema.DropIndex) bool {\n\t\t\t\t\t\tif !drop.I.Unique || len(drop.I.Parts) > len(c.I.Parts) {\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor _, p1 := range c.I.Parts {\n\t\t\t\t\t\t\tswitch {\n\t\t\t\t\t\t\tcase p1.C != nil:\n\t\t\t\t\t\t\t\tif p.File.ColumnSpan(m.T, p1.C)&sqlcheck.SpanAdded == 0 && !slices.ContainsFunc(drop.I.Parts, func(p2 *schema.IndexPart) bool {\n\t\t\t\t\t\t\t\t\treturn p2.C != nil && p2.C.Name == p1.C.Name\n\t\t\t\t\t\t\t\t}) {\n\t\t\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcase p1.X != nil:\n\t\t\t\t\t\t\t\tif rx1, ok := p1.X.(*schema.RawExpr); ok && !slices.ContainsFunc(drop.I.Parts, func(p2 *schema.IndexPart) bool {\n\t\t\t\t\t\t\t\t\trx2, ok := p2.X.(*schema.RawExpr)\n\t\t\t\t\t\t\t\t\treturn ok && rx1.X == rx2.X\n\t\t\t\t\t\t\t\t}) {\n\t\t\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tnames := func() []string {\n\t\t\t\t\t\tvar names []string\n\t\t\t\t\t\tfor i := range c.I.Parts {\n\t\t\t\t\t\t\t// We consider a column a non-new column if\n\t\t\t\t\t\t\t// it was not added in this migration file.\n\t\t\t\t\t\t\tif column := c.I.Parts[i].C; column != nil && p.File.ColumnSpan(m.T, column)&sqlcheck.SpanAdded == 0 {\n\t\t\t\t\t\t\t\tnames = append(names, fmt.Sprintf(\"%q\", column.Name))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn names\n\t\t\t\t\t}()\n\t\t\t\t\t// A unique index was added on an existing columns.\n\t\t\t\t\tif c.I.Unique && len(names) > 0 {\n\t\t\t\t\t\ts := fmt.Sprintf(\"columns %s contain\", strings.Join(names, \", \"))\n\t\t\t\t\t\tif len(names) == 1 {\n\t\t\t\t\t\t\ts = fmt.Sprintf(\"column %s contains\", names[0])\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\t\tCode: codeAddUniqueI,\n\t\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\t\tText: fmt.Sprintf(\"Adding a unique index %q on table %q might fail in case %s duplicate entries\", c.I.Name, m.T.Name, s),\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\tcase *schema.ModifyIndex:\n\t\t\t\t\tif c.Change.Is(schema.ChangeUnique) && c.To.Unique && p.File.IndexSpan(m.T, c.To)&sqlcheck.SpanAdded == 0 {\n\t\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\t\tCode: codeModUniqueI,\n\t\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\t\tText: fmt.Sprintf(\"Modifying an index %q on table %q might fail in case of duplicate entries\", c.To.Name, m.T.Name),\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\tcase *schema.AddColumn:\n\t\t\t\t\t// In case the column is nullable without default\n\t\t\t\t\t// value and the table was not added in this file.\n\t\t\t\t\tif a.Handler.AddNotNull != nil && !c.C.Type.Null && c.C.Default == nil && p.File.TableSpan(m.T)&sqlcheck.SpanAdded != 1 {\n\t\t\t\t\t\td, err := a.Handler.AddNotNull(&ColumnPass{Pass: p, Change: sc, Table: m.T, Column: c.C})\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor i := range d {\n\t\t\t\t\t\t\t// In case there is no driver-specific code.\n\t\t\t\t\t\t\tif d[i].Code == \"\" {\n\t\t\t\t\t\t\t\td[i].Code = codeAddNotNullC\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdiags = append(diags, d...)\n\t\t\t\t\t}\n\t\t\t\tcase *schema.ModifyColumn:\n\t\t\t\t\tswitch {\n\t\t\t\t\tcase p.File.TableSpan(m.T)&sqlcheck.SpanAdded == 1 || !(c.From.Type.Null && !c.To.Type.Null) || HasNotNullCheck(p, c.From):\n\t\t\t\t\tcase a.ModifyNotNull != nil:\n\t\t\t\t\t\td, err := a.Handler.ModifyNotNull(&ColumnPass{Pass: p, Change: sc, Table: m.T, Column: c.To})\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor i := range d {\n\t\t\t\t\t\t\t// In case there is no driver-specific code.\n\t\t\t\t\t\t\tif d[i].Code == \"\" {\n\t\t\t\t\t\t\t\td[i].Code = codeModNotNullC\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdiags = append(diags, d...)\n\t\t\t\t\t// In case the altered column was not added in this file, and the column\n\t\t\t\t\t// was changed nullable to non-nullable without back filling it with values.\n\t\t\t\t\tcase !ColumnFilled(p, m.T, c.From, sc.Stmt.Pos):\n\t\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\t\tCode: codeModNotNullC,\n\t\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\t\tText: fmt.Sprintf(\"Modifying nullable column %q to non-nullable might fail in case it contains NULL values\", c.To.Name),\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\n// Report provides standard reporting for data-dependent changes. Drivers that\n// decorate this Analyzer should call this function to get consistent reporting\n// between dialects.\nfunc (a *Analyzer) Report(p *sqlcheck.Pass, diags []sqlcheck.Diagnostic) error {\n\tconst reportText = \"data dependent changes detected\"\n\tif len(diags) > 0 {\n\t\tp.Reporter.WriteReport(sqlcheck.Report{Text: reportText, Diagnostics: diags})\n\t\tif sqlx.V(a.Error) {\n\t\t\treturn errors.New(reportText)\n\t\t}\n\t}\n\treturn nil\n}\n\n// ColumnFilled checks if the column was filled with values before the given position.\nfunc ColumnFilled(p *sqlcheck.Pass, t *schema.Table, c *schema.Column, pos int) bool {\n\t// The parser used for parsing this file can check if the\n\t// given nullable column was filled before the given position.\n\tpr, ok := p.File.Parser.(interface {\n\t\tColumnFilledBefore([]*migrate.Stmt, *schema.Table, *schema.Column, int) (bool, error)\n\t})\n\tif !ok {\n\t\treturn false\n\t}\n\tstmts, err := migrate.FileStmtDecls(p.Dev, p.File)\n\tif err != nil {\n\t\treturn false\n\t}\n\tfilled, _ := pr.ColumnFilledBefore(stmts, t, c, pos)\n\treturn filled\n}\n\n// HasNotNullCheck checks if the given column has a check constraint with a NOT NULL check.\n// In case a CHECK exists, this reduces the risk for data-depend conflicts when changing\n// a nullable column to non-nullable.\nfunc HasNotNullCheck(p *sqlcheck.Pass, c *schema.Column) bool {\n\tpr, ok := p.File.Parser.(interface {\n\t\tCheckNotNullFor(*schema.Check, string) (bool, error)\n\t})\n\treturn ok && slices.ContainsFunc(c.Attrs, func(a schema.Attr) bool {\n\t\tck, ok := a.(*schema.Check)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\t\tv, err := pr.CheckNotNullFor(ck, c.Name)\n\t\treturn err == nil && v\n\t})\n}\n"
  },
  {
    "path": "sql/sqlcheck/datadepend/datadepend_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage datadepend_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlcheck/datadepend\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestAnalyzer_AddUniqueIndex(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE users\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"a\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"b\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"c\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"d\"),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t\t\t// Ignore new created columns.\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\t\t\tC: schema.NewColumn(\"a\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\t\t\tI: schema.NewUniqueIndex(\"idx_a\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"a\")),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t// Report on existing column.\n\t\t\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\t\t\tI: schema.NewUniqueIndex(\"idx_b\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"b\")),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t// Report on existing columns.\n\t\t\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\t\t\tI: schema.NewUniqueIndex(\"idx_c_d\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"c\"),\n\t\t\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"d\"),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := datadepend.New(nil, datadepend.Handler{})\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"data dependent changes detected\", report.Text)\n\trequire.Len(t, report.Diagnostics, 2)\n\trequire.Equal(t, `Adding a unique index \"idx_b\" on table \"users\" might fail in case column \"b\" contains duplicate entries`, report.Diagnostics[0].Text)\n\trequire.Equal(t, `Adding a unique index \"idx_c_d\" on table \"users\" might fail in case columns \"c\", \"d\" contain duplicate entries`, report.Diagnostics[1].Text)\n\n\t// Dropping index and then creating it again with added columns should not report any diagnostics.\n\t*report = sqlcheck.Report{}\n\tpass.File = &sqlcheck.File{\n\t\tChanges: []*sqlcheck.Change{\n\t\t\t{\n\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\tText: \"ALTER TABLE users\",\n\t\t\t\t},\n\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\tschema.NewColumn(\"a\"),\n\t\t\t\t\t\t\t\tschema.NewColumn(\"b\"),\n\t\t\t\t\t\t\t\tschema.NewColumn(\"c\"),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropIndex{\n\t\t\t\t\t\t\t\tI: schema.NewUniqueIndex(\"idx_a_b\").\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"a\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"b\"),\n\t\t\t\t\t\t\t\t\t).\n\t\t\t\t\t\t\t\t\tAddExprs(&schema.RawExpr{X: \"a + b\"}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddColumn{C: schema.NewColumn(\"c\")},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: schema.NewUniqueIndex(\"idx_a_b_c\").\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"a\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"b\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"c\"),\n\t\t\t\t\t\t\t\t\t).\n\t\t\t\t\t\t\t\t\tAddExprs(&schema.RawExpr{X: \"a + b\"}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\taz, err = datadepend.New(nil, datadepend.Handler{})\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.NoError(t, err)\n\trequire.Len(t, report.Diagnostics, 0)\n}\n\nfunc TestAnalyzer_ModifyUniqueIndex(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE users\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"a\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"b\"),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t\t\t// Ignore new created columns.\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\t\t\tC: schema.NewColumn(\"a\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&schema.ModifyIndex{\n\t\t\t\t\t\t\t\t\t\tFrom: schema.NewIndex(\"idx_a\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"a\")),\n\t\t\t\t\t\t\t\t\t\tTo: schema.NewUniqueIndex(\"idx_a\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"a\")),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t// Report on existing columns.\n\t\t\t\t\t\t\t\t\t&schema.ModifyIndex{\n\t\t\t\t\t\t\t\t\t\tFrom: schema.NewIndex(\"idx_b\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"b\")),\n\t\t\t\t\t\t\t\t\t\tTo: schema.NewUniqueIndex(\"idx_b\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"b\")),\n\t\t\t\t\t\t\t\t\t\tChange: schema.ChangeUnique,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := datadepend.New(nil, datadepend.Handler{})\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"data dependent changes detected\", report.Text)\n\trequire.Len(t, report.Diagnostics, 1)\n\trequire.Equal(t, `Modifying an index \"idx_b\" on table \"users\" might fail in case of duplicate entries`, report.Diagnostics[0].Text)\n}\n\nfunc TestAnalyzer_ModifyNullability(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE users\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewNullIntColumn(\"a\", \"int\"),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\t\t\tFrom:   schema.NewNullIntColumn(\"a\", \"int\"),\n\t\t\t\t\t\t\t\t\t\tTo:     schema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\t\t\t\t\t\tChange: schema.ChangeNull,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := datadepend.New(nil, datadepend.Handler{})\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"data dependent changes detected\", report.Text)\n\trequire.Len(t, report.Diagnostics, 1)\n\trequire.Equal(t, `Modifying nullable column \"a\" to non-nullable might fail in case it contains NULL values`, report.Diagnostics[0].Text)\n}\n\nfunc TestAnalyzer_Options(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE users\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"a\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewColumn(\"b\"),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\t\t\tI: schema.NewIndex(\"idx_a\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"a\")),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&schema.ModifyIndex{\n\t\t\t\t\t\t\t\t\t\tFrom: schema.NewIndex(\"idx_b\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"b\")),\n\t\t\t\t\t\t\t\t\t\tTo: schema.NewUniqueIndex(\"idx_b\").\n\t\t\t\t\t\t\t\t\t\t\tAddColumns(schema.NewColumn(\"b\")),\n\t\t\t\t\t\t\t\t\t\tChange: schema.ChangeUnique,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := datadepend.New(&schemahcl.Resource{\n\t\tChildren: []*schemahcl.Resource{\n\t\t\t{\n\t\t\t\tType: \"data_depend\",\n\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\tschemahcl.BoolAttr(\"error\", true),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}, datadepend.Handler{})\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.EqualError(t, err, \"data dependent changes detected\")\n\trequire.NotNil(t, report)\n}\n\ntype testFile struct {\n\tname string\n\tmigrate.File\n}\n\nfunc (t testFile) Name() string {\n\treturn t.name\n}\n"
  },
  {
    "path": "sql/sqlcheck/destructive/destructive.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage destructive\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n)\n\n// Analyzer checks for destructive changes.\ntype Analyzer struct {\n\tsqlcheck.Options\n}\n\n// New creates a new destructive changes Analyzer with the given options.\nfunc New(r *schemahcl.Resource) (*Analyzer, error) {\n\taz := &Analyzer{}\n\taz.Error = sqlx.P(true)\n\tif r, ok := r.Resource(az.Name()); ok {\n\t\tif err := r.As(&az.Options); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sql/sqlcheck: parsing destructive check options: %w\", err)\n\t\t}\n\t}\n\treturn az, nil\n}\n\n// List of codes.\nvar (\n\tcodeDropS = sqlcheck.Code(\"DS101\")\n\tcodeDropT = sqlcheck.Code(\"DS102\")\n\tcodeDropC = sqlcheck.Code(\"DS103\")\n)\n\n// Name of the analyzer. Implements the sqlcheck.NamedAnalyzer interface.\nfunc (*Analyzer) Name() string {\n\treturn \"destructive\"\n}\n\n// Analyze implements sqlcheck.Analyzer.\nfunc (a *Analyzer) Analyze(_ context.Context, p *sqlcheck.Pass) error {\n\tvar (\n\t\tedits []*migrate.Stmt\n\t\tdiags []sqlcheck.Diagnostic\n\t)\n\tfor _, sc := range p.File.Changes {\n\t\tfor _, c := range sc.Changes {\n\t\t\tswitch c := c.(type) {\n\t\t\tcase *schema.DropSchema:\n\t\t\t\tif p.File.SchemaSpan(c.S) != sqlcheck.SpanTemporary {\n\t\t\t\t\tvar text string\n\t\t\t\t\tswitch n := len(c.S.Tables); {\n\t\t\t\t\tcase n == 0:\n\t\t\t\t\t\ttext = fmt.Sprintf(\"Dropping schema %q\", c.S.Name)\n\t\t\t\t\tcase n == 1:\n\t\t\t\t\t\ttext = fmt.Sprintf(\"Dropping non-empty schema %q with 1 table\", c.S.Name)\n\t\t\t\t\tcase n > 1:\n\t\t\t\t\t\ttext = fmt.Sprintf(\"Dropping non-empty schema %q with %d tables\", c.S.Name, n)\n\t\t\t\t\t}\n\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\tCode: codeDropS,\n\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\tText: text,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\tcase *schema.DropTable:\n\t\t\t\tif p.File.SchemaSpan(c.T.Schema) != sqlcheck.SpanDropped && p.File.TableSpan(c.T) != sqlcheck.SpanTemporary && !a.hasEmptyTableCheck(p, c.T) {\n\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\tCode: codeDropT,\n\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\tText: fmt.Sprintf(\"Dropping table %q\", c.T.Name),\n\t\t\t\t\t\tSuggestedFixes: []sqlcheck.SuggestedFix{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMessage: fmt.Sprintf(\"Add a pre-migration check to ensure table %q is empty before dropping it\", c.T.Name),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\tif stmt, err := a.emptyTableCheckStmt(p, c.T); err == nil {\n\t\t\t\t\t\tedits = append(edits, stmt)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase *schema.ModifyTable:\n\t\t\t\tvar names []string\n\t\t\t\tfor i := range c.Changes {\n\t\t\t\t\td, ok := c.Changes[i].(*schema.DropColumn)\n\t\t\t\t\tif !ok || p.File.ColumnSpan(c.T, d.C) == sqlcheck.SpanTemporary {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif g := (schema.GeneratedExpr{}); (!sqlx.Has(d.C.Attrs, &g) || strings.ToUpper(g.Type) != \"VIRTUAL\") && !a.hasEmptyColumnCheck(p, c.T, d.C) {\n\t\t\t\t\t\tnames = append(names, strconv.Quote(d.C.Name))\n\t\t\t\t\t\tif stmt, err := a.emptyColumnCheckStmt(p, c.T, d.C.Name); err == nil {\n\t\t\t\t\t\t\tedits = append(edits, stmt)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tswitch n := len(names); {\n\t\t\t\tcase n == 1:\n\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\tCode: codeDropC,\n\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\tText: fmt.Sprintf(\"Dropping non-virtual column %s\", names[0]),\n\t\t\t\t\t\tSuggestedFixes: []sqlcheck.SuggestedFix{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMessage: fmt.Sprintf(\"Add a pre-migration check to ensure column %s is NULL before dropping it\", names[0]),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\tcase n > 1:\n\t\t\t\t\t// All changes generated by the same statement (same position).\n\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\tCode: codeDropC,\n\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\tText: fmt.Sprintf(\"Dropping non-virtual columns %s and %s\", strings.Join(names[:n-1], \", \"), names[n-1]),\n\t\t\t\t\t\tSuggestedFixes: []sqlcheck.SuggestedFix{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tMessage: fmt.Sprintf(\"Add pre-migration checks to ensure columns %s and %s are NULL before dropping them\", strings.Join(names[:n-1], \", \"), names[n-1]),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif len(diags) > 0 {\n\t\tconst reportText = \"destructive changes detected\"\n\t\tp.Reporter.WriteReport(\n\t\t\twithSuggestion(p, sqlcheck.Report{Text: reportText, Diagnostics: diags}, edits),\n\t\t)\n\t\tif sqlx.V(a.Error) {\n\t\t\treturn errors.New(reportText)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "sql/sqlcheck/destructive/destructive_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage destructive\n\nimport (\n\t\"errors\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n)\n\nfunc (*Analyzer) hasEmptyTableCheck(*sqlcheck.Pass, *schema.Table) bool {\n\treturn false // unimplemented.\n}\n\nfunc (*Analyzer) hasEmptyColumnCheck(*sqlcheck.Pass, *schema.Table, *schema.Column) bool {\n\treturn false // unimplemented.\n}\n\nfunc (*Analyzer) emptyTableCheckStmt(*sqlcheck.Pass, *schema.Table) (*migrate.Stmt, error) {\n\treturn nil, errors.New(\"unimplemented\")\n}\n\nfunc (*Analyzer) emptyColumnCheckStmt(*sqlcheck.Pass, *schema.Table, string) (*migrate.Stmt, error) {\n\treturn nil, errors.New(\"unimplemented\")\n}\n\nfunc withSuggestion(_ *sqlcheck.Pass, r sqlcheck.Report, _ []*migrate.Stmt) sqlcheck.Report {\n\treturn r // unimplemented.\n}\n"
  },
  {
    "path": "sql/sqlcheck/destructive/destructive_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage destructive_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlcheck/destructive\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestAnalyzer_DropTable(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"DROP TABLE `users`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.DropTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"DROP TABLE `posts`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.DropTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"CREATE TABLE `posts`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.AddTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := destructive.New(nil)\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.Error(t, err)\n\trequire.Equal(t, \"destructive changes detected\", report.Text)\n\trequire.Len(t, report.Diagnostics, 2)\n\trequire.Equal(t, `Dropping table \"users\"`, report.Diagnostics[0].Text)\n\trequire.Equal(t, `Dropping table \"posts\"`, report.Diagnostics[1].Text)\n}\n\nfunc TestAnalyzer_SkipTemporaryTable(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"DROP TABLE `users`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.AddTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.DropTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := destructive.New(nil)\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.NoError(t, err)\n\trequire.Nil(t, report, \"no report\")\n}\n\nfunc TestAnalyzer_DropSchema(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"DROP SCHEMA `test`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.DropSchema{\n\t\t\t\t\t\t\t\tS: schema.New(\"test\").\n\t\t\t\t\t\t\t\t\tAddTables(\n\t\t\t\t\t\t\t\t\t\tschema.NewTable(\"users\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewTable(\"orders\"),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"DROP SCHEMA `market`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.DropSchema{\n\t\t\t\t\t\t\t\tS: schema.New(\"market\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"CREATE DATABASE `market`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.AddSchema{\n\t\t\t\t\t\t\t\tS: schema.New(\"market\"),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := destructive.New(&schemahcl.Resource{\n\t\tChildren: []*schemahcl.Resource{\n\t\t\t{\n\t\t\t\tType: \"destructive\",\n\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\tschemahcl.BoolAttr(\"error\", false),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"destructive changes detected\", report.Text)\n\trequire.Len(t, report.Diagnostics, 2)\n\trequire.Equal(t, `Dropping non-empty schema \"test\" with 2 tables`, report.Diagnostics[0].Text)\n\trequire.Equal(t, `Dropping schema \"market\"`, report.Diagnostics[1].Text)\n}\n\nfunc TestAnalyzer_DropColumn(t *testing.T) {\n\tvar (\n\t\treport sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{Name: \"mysql\"},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `pets`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"pets\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t\t\t&schema.DropColumn{\n\t\t\t\t\t\t\t\t\t\tC: schema.NewColumn(\"c\").\n\t\t\t\t\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Type: \"STORED\"}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `pets`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifySchema{\n\t\t\t\t\t\t\t\tS: schema.New(\"test\"),\n\t\t\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t\t\t&schema.ModifyAttr{\n\t\t\t\t\t\t\t\t\t\tFrom: &schema.Charset{V: \"utf8\"},\n\t\t\t\t\t\t\t\t\t\tTo:   &schema.Charset{V: \"latin1\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := destructive.New(&schemahcl.Resource{\n\t\tChildren: []*schemahcl.Resource{\n\t\t\t{\n\t\t\t\tType: \"destructive\",\n\t\t\t\tAttrs: []*schemahcl.Attr{\n\t\t\t\t\tschemahcl.BoolAttr(\"error\", false),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t})\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.NoError(t, err)\n\trequire.Len(t, report.Diagnostics, 1)\n\trequire.Equal(t, \"destructive changes detected\", report.Text)\n\trequire.Equal(t, `Dropping non-virtual column \"c\"`, report.Diagnostics[0].Text)\n\trequire.Len(t, report.Diagnostics[0].SuggestedFixes, 1)\n\trequire.Equal(t, \"Add a pre-migration check to ensure column \\\"c\\\" is NULL before dropping it\", report.Diagnostics[0].SuggestedFixes[0].Message)\n}\n\ntype testFile struct {\n\tname string\n\tmigrate.File\n}\n\nfunc (t testFile) Name() string {\n\treturn t.name\n}\n"
  },
  {
    "path": "sql/sqlcheck/incompatible/incompatible.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage incompatible\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n)\n\n// Analyzer checks for backwards-incompatible (breaking) changes.\ntype Analyzer struct {\n\tsqlcheck.Options\n}\n\n// New creates a new backwards-incompatible changes Analyzer with the given options.\nfunc New(r *schemahcl.Resource) (*Analyzer, error) {\n\taz := &Analyzer{}\n\tif r, ok := r.Resource(az.Name()); ok {\n\t\tif err := r.As(&az.Options); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sql/sqlcheck: parsing incompatible check options: %w\", err)\n\t\t}\n\t}\n\treturn az, nil\n}\n\n// List of codes.\nvar (\n\tcodeRenameT = sqlcheck.Code(\"BC101\")\n\tcodeRenameC = sqlcheck.Code(\"BC102\")\n)\n\n// Name of the analyzer. Implements the sqlcheck.NamedAnalyzer interface.\nfunc (*Analyzer) Name() string {\n\treturn \"incompatible\"\n}\n\n// Analyze implements sqlcheck.Analyzer.\nfunc (a *Analyzer) Analyze(_ context.Context, p *sqlcheck.Pass) error {\n\tvar diags []sqlcheck.Diagnostic\n\tfor i, sc := range p.File.Changes {\n\t\tfor _, c := range sc.Changes {\n\t\t\tswitch c := c.(type) {\n\t\t\tcase *schema.RenameTable:\n\t\t\t\tif p.File.SchemaSpan(c.From.Schema)&sqlcheck.SpanAdded == 0 && p.File.TableSpan(c.From)&sqlcheck.SpanAdded == 0 &&\n\t\t\t\t\t!ViewForRenamedT(p, c.From.Name, c.To.Name, sc.Stmt.Pos) {\n\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\tCode: codeRenameT,\n\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\tText: fmt.Sprintf(\"Renaming table %q to %q\", c.From.Name, c.To.Name),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\tcase *schema.ModifyTable:\n\t\t\t\tfor j := range c.Changes {\n\t\t\t\t\tswitch mc := c.Changes[j].(type) {\n\t\t\t\t\tcase *schema.RenameColumn:\n\t\t\t\t\t\tif p.File.TableSpan(c.T)&sqlcheck.SpanAdded == 0 && !wasAddedBack(p.File.Changes[i:], mc.From) {\n\t\t\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\t\t\tCode: codeRenameC,\n\t\t\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\t\t\tText: fmt.Sprintf(\"Renaming column %q to %q\", mc.From.Name, mc.To.Name),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\tcase *schema.ModifyColumn:\n\t\t\t\t\t\tif p.File.TableSpan(c.T)&sqlcheck.SpanAdded == 0 && mc.From.Name != mc.To.Name && !wasAddedBack(p.File.Changes[i:], mc.From) {\n\t\t\t\t\t\t\tdiags = append(diags, sqlcheck.Diagnostic{\n\t\t\t\t\t\t\t\tCode: codeRenameC,\n\t\t\t\t\t\t\t\tPos:  sc.Stmt.Pos,\n\t\t\t\t\t\t\t\tText: fmt.Sprintf(\"Renaming column %q to %q\", mc.From.Name, mc.To.Name),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif len(diags) > 0 {\n\t\tconst reportText = \"backward incompatible changes detected\"\n\t\tp.Reporter.WriteReport(sqlcheck.Report{Text: reportText, Diagnostics: diags})\n\t\tif sqlx.V(a.Error) {\n\t\t\treturn errors.New(reportText)\n\t\t}\n\t}\n\treturn nil\n}\n\n// ViewForRenamedT checks if a view was created was a table that was renamed after the given position.\nfunc ViewForRenamedT(p *sqlcheck.Pass, old, new string, pos int) bool {\n\t// The parser used for parsing this file can check if the\n\t// given nullable column was filled before the given position.\n\tpr, ok := p.File.Parser.(interface {\n\t\tCreateViewAfter(stmts []*migrate.Stmt, old, new string, pos int) (bool, error)\n\t})\n\tif !ok {\n\t\treturn false\n\t}\n\tstmts, err := migrate.FileStmtDecls(p.Dev, p.File)\n\tif err != nil {\n\t\treturn false\n\t}\n\tcreated, _ := pr.CreateViewAfter(stmts, old, new, pos)\n\treturn created\n}\n\nfunc wasAddedBack(changes []*sqlcheck.Change, old *schema.Column) bool {\n\tfor _, sc := range changes {\n\t\tfor _, c := range sc.Changes {\n\t\t\tm, ok := c.(*schema.ModifyTable)\n\t\t\tif !ok {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// Although it is recommended to add the renamed column as generated,\n\t\t\t// adding it as a regular column is considered backwards compatible.\n\t\t\tif schema.Changes(m.Changes).IndexAddColumn(old.Name) != -1 {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "sql/sqlcheck/incompatible/incompatible_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage incompatible_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlcheck/incompatible\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestAnalyzer_RenameColumn(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"CREATE TABLE `users` (`id` int)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.AddTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t// Skip column that was added in the same file.\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `users` RENAME COLUMN `id` TO `uid`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"uid\", \"int\")),\n\t\t\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t\t\t&schema.RenameColumn{\n\t\t\t\t\t\t\t\t\t\tFrom: schema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t\t\t\t\t\tTo:   schema.NewIntColumn(\"uid\", \"int\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t// Skip if a new generated column was added with the previous name.\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `pets` RENAME COLUMN `id` TO `uid`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"pets\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"uid\", \"int\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\").\n\t\t\t\t\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{\n\t\t\t\t\t\t\t\t\t\t\t\tExpr: \"uid\", // point to the renamed column.\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t\t\t&schema.RenameColumn{\n\t\t\t\t\t\t\t\t\t\tFrom: schema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t\t\t\t\t\tTo:   schema.NewIntColumn(\"uid\", \"int\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\t\t\tC: schema.NewIntColumn(\"id\", \"int\").\n\t\t\t\t\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{\n\t\t\t\t\t\t\t\t\t\t\t\tExpr: \"uid\", // point to the renamed column.\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t// Skip if a new column was added with the previous name in consecutive statement.\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `pets` RENAME COLUMN `id` TO `uid`;ALTER TABLE `pets` ADD COLUMN `id` int;\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"pets\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"uid\", \"int\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\").\n\t\t\t\t\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{\n\t\t\t\t\t\t\t\t\t\t\t\tExpr: \"uid\", // point to the renamed column.\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t\t\t&schema.RenameColumn{\n\t\t\t\t\t\t\t\t\t\tFrom: schema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t\t\t\t\t\tTo:   schema.NewIntColumn(\"uid\", \"int\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"pets\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"uid\", \"int\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\").\n\t\t\t\t\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{\n\t\t\t\t\t\t\t\t\t\t\t\tExpr: \"uid\", // point to the renamed column.\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\t\t\tC: schema.NewIntColumn(\"id\", \"int\").\n\t\t\t\t\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{\n\t\t\t\t\t\t\t\t\t\t\t\tExpr: \"uid\", // point to the renamed column.\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t// Detect rename.\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `cards` RENAME COLUMN `id` TO `uid`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"cards\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewIntColumn(\"uid\", \"int\"),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t\t\t&schema.RenameColumn{\n\t\t\t\t\t\t\t\t\t\tFrom: schema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t\t\t\t\t\tTo:   schema.NewIntColumn(\"uid\", \"int\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := incompatible.New(nil)\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, report)\n\trequire.Len(t, report.Diagnostics, 1)\n\trequire.Equal(t, \"BC102\", report.Diagnostics[0].Code)\n\trequire.Equal(t, `Renaming column \"id\" to \"uid\"`, report.Diagnostics[0].Text)\n}\n\nfunc TestAnalyzer_RenameTable(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{\n\t\t\t\t\tname: \"1.sql\",\n\t\t\t\t\tstmts: []*migrate.Stmt{\n\t\t\t\t\t\t{Text: \"CREATE TABLE `users` (`id` int)\", Pos: 1},\n\t\t\t\t\t\t{Text: \"ALTER TABLE `users` RENAME TO `Users`\", Pos: 2},\n\t\t\t\t\t\t{Text: \"ALTER TABLE `pets` RENAME TO `Pets`\", Pos: 3},\n\t\t\t\t\t\t{Text: \"ALTER TABLE `cards` RENAME TO `Cards`\", Pos: 4},\n\t\t\t\t\t\t{Text: \"CREATE VIEW `cards` AS SELECT * FROM `Cards`\", Pos: 5},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tParser: testParser{matchOn: \"cards\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"CREATE TABLE `users` (`id` int)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.AddTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t// Skip table that was added in the same file.\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `users` RENAME TO `Users`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.RenameTable{\n\t\t\t\t\t\t\t\tFrom: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t\tTo: schema.NewTable(\"Users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t// Detect rename.\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `pets` RENAME TO `Pets`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.RenameTable{\n\t\t\t\t\t\t\t\tFrom: schema.NewTable(\"pets\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t\tTo: schema.NewTable(\"Pets\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t// Skip rename if a view was created.\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `cards` RENAME TO `Cards`\",\n\t\t\t\t\t\t\tPos:  4,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.RenameTable{\n\t\t\t\t\t\t\t\tFrom: schema.NewTable(\"cards\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t\tTo: schema.NewTable(\"Cards\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"test\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\taz, err := incompatible.New(nil)\n\trequire.NoError(t, err)\n\terr = az.Analyze(context.Background(), pass)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, report)\n\trequire.Len(t, report.Diagnostics, 1)\n\trequire.Equal(t, \"BC101\", report.Diagnostics[0].Code)\n\trequire.Equal(t, `Renaming table \"pets\" to \"Pets\"`, report.Diagnostics[0].Text)\n}\n\ntype testFile struct {\n\tname  string\n\tstmts []*migrate.Stmt\n\tmigrate.File\n}\n\nfunc (t testFile) Name() string {\n\treturn t.name\n}\n\nfunc (t testFile) StmtDecls() ([]*migrate.Stmt, error) {\n\treturn t.stmts, nil\n}\n\ntype testParser struct{ matchOn string }\n\nfunc (t testParser) CreateViewAfter(_ []*migrate.Stmt, old, _ string, _ int) (bool, error) {\n\treturn t.matchOn == old, nil\n}\n"
  },
  {
    "path": "sql/sqlcheck/sqlcheck.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Package sqlcheck provides interfaces for analyzing the contents of SQL files\n// to generate insights on the safety of many kinds of changes to database\n// schemas. With this package developers may define an Analyzer that can be used\n// to diagnose the impact of SQL statements on the target database. For instance,\n// The `destructive` package exposes an Analyzer that detects destructive changes\n// to the database schema, such as the dropping of tables or columns.\npackage sqlcheck\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n)\n\ntype (\n\t// An Analyzer describes a migration file analyzer.\n\tAnalyzer interface {\n\t\t// Analyze executes the analysis function.\n\t\tAnalyze(context.Context, *Pass) error\n\t}\n\n\t// A NamedAnalyzer describes an Analyzer that has a name.\n\tNamedAnalyzer interface {\n\t\tAnalyzer\n\t\t// Name of the analyzer. Identifies the analyzer\n\t\t// in configuration and linting passes.\n\t\tName() string\n\t}\n\n\t// A Pass provides information to the Analyzer.Analyze function\n\t// that applies a specific analyzer to an SQL file.\n\tPass struct {\n\t\t// A migration file and the changes it describes.\n\t\tFile *File\n\n\t\t// Dev is a driver-specific environment used to execute analysis work.\n\t\tDev *sqlclient.Client\n\n\t\t// Report reports analysis reports.\n\t\tReporter ReportWriter\n\t}\n\n\t// File represents a parsed version of a migration file.\n\tFile struct {\n\t\tmigrate.File\n\n\t\t// Changes represents the list of changes this file represents.\n\t\tChanges []*Change\n\n\t\t// Sum represents a summary of changes this file represents. For example,\n\t\t// in case of a file that contains exactly two statements, and the first\n\t\t// statement is reverted by the one after it, the Sum is nil.\n\t\tSum schema.Changes\n\n\t\t// From, To holds the representation of schema\n\t\t// before and after the file was executed.\n\t\tFrom, To *schema.Realm\n\n\t\t// A Parser that may be used for parsing this file. It sets to any as the contract\n\t\t// between checks and their parsers can vary. For example, in case of running checks\n\t\t// from CLI, the injected parser can be found in cmd/atlas/internal/sqlparse.Parser.\n\t\tParser any\n\n\t\t// schema spans. lazily initialized.\n\t\tspans map[string]*schemaSpan\n\t}\n\n\t// A Change in a migration file.\n\tChange struct {\n\t\tschema.Changes               // The actual changes.\n\t\tStmt           *migrate.Stmt // The SQL statement generated this change.\n\t}\n\n\t// A Report describes an analysis report with an optional specific diagnostic.\n\tReport struct {\n\t\tText           string         `json:\"Text\"`                     // Report text.\n\t\tDesc           string         `json:\"Desc,omitempty\"`           // Optional description (secondary text).\n\t\tDiagnostics    []Diagnostic   `json:\"Diagnostics,omitempty\"`    // Report diagnostics.\n\t\tSuggestedFixes []SuggestedFix `json:\"SuggestedFixes,omitempty\"` // Report-level suggested fixes.\n\t}\n\n\t// A Diagnostic is a text associated with a specific position of a statement in a file.\n\tDiagnostic struct {\n\t\tPos            int            `json:\"Pos\"`                      // Diagnostic position.\n\t\tText           string         `json:\"Text\"`                     // Diagnostic text.\n\t\tCode           string         `json:\"Code\"`                     // Code describes the check. For example, DS101\n\t\tSuggestedFixes []SuggestedFix `json:\"SuggestedFixes,omitempty\"` // Fixes to this specific diagnostics (statement-level).\n\t}\n\n\t// A SuggestedFix is a change associated with a diagnostic that can\n\t// be applied to fix the issue. Both the message and the text edit\n\t// are optional.\n\tSuggestedFix struct {\n\t\tMessage  string    `json:\"Message\"`\n\t\tTextEdit *TextEdit `json:\"TextEdit,omitempty\"`\n\t}\n\n\t// A TextEdit represents a code changes in a file.\n\t// The suggested edits are line-based starting from 1.\n\tTextEdit struct {\n\t\tLine    int    `json:\"Line\"`    // Start line to edit.\n\t\tEnd     int    `json:\"End\"`     // End line to edit.\n\t\tNewText string `json:\"NewText\"` // New text to replace.\n\t}\n\n\t// ReportWriter represents a writer for analysis reports.\n\tReportWriter interface {\n\t\tWriteReport(Report)\n\t}\n\n\t// Options defines a generic configuration options for analyzers.\n\tOptions struct {\n\t\t// Error indicates if an analyzer should\n\t\t// error in case a Diagnostic was found.\n\t\tError *bool `spec:\"error\"`\n\n\t\t// Allow drivers to extend the configuration.\n\t\tschemahcl.DefaultExtension\n\t}\n)\n\n// SuggestFix appends a suggested fix to the diagnostic.\nfunc (d *Diagnostic) SuggestFix(m string, e *TextEdit) {\n\td.SuggestedFixes = append(d.SuggestedFixes, SuggestedFix{Message: m, TextEdit: e})\n}\n\n// Analyzers implements Analyzer.\ntype Analyzers []Analyzer\n\n// Analyze implements Analyzer.\nfunc (a Analyzers) Analyze(ctx context.Context, p *Pass) error {\n\tfor _, a := range a {\n\t\tif err := a.Analyze(ctx, p); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// AnalyzerFunc allows using ordinary functions as analyzers.\ntype AnalyzerFunc func(ctx context.Context, p *Pass) error\n\n// Analyze calls f.\nfunc (f AnalyzerFunc) Analyze(ctx context.Context, p *Pass) error {\n\treturn f(ctx, p)\n}\n\n// ReportWriterFunc is a function that implements Reporter.\ntype ReportWriterFunc func(Report)\n\n// WriteReport calls f(r).\nfunc (f ReportWriterFunc) WriteReport(r Report) {\n\tf(r)\n}\n\n// ResourceSpan describes the lifespan of a resource\n// in perspective to the migration file.\ntype ResourceSpan uint\n\nconst (\n\t// SpanUnknown describes unknown lifespan.\n\t// e.g. resource may exist before this file.\n\tSpanUnknown ResourceSpan = iota\n\n\t// SpanAdded describes that a span of\n\t// a resource was started in this file.\n\tSpanAdded\n\n\t// SpanDropped describes that a span of\n\t// a resource was ended in this file.\n\tSpanDropped\n\n\t// SpanTemporary indicates that a resource lifetime\n\t// was started and ended in this file (CREATE and DROP).\n\tSpanTemporary = SpanAdded | SpanDropped\n)\n\n// SchemaSpan returns the span information for the schema.\nfunc (f *File) SchemaSpan(s *schema.Schema) ResourceSpan {\n\treturn f.schemaSpan(s).state\n}\n\n// TableSpan returns the span information for the table.\nfunc (f *File) TableSpan(t *schema.Table) ResourceSpan {\n\treturn f.tableSpan(t).state\n}\n\n// ColumnSpan returns the span information for the column.\nfunc (f *File) ColumnSpan(t *schema.Table, c *schema.Column) ResourceSpan {\n\treturn f.tableSpan(t).columns[c.Name]\n}\n\n// IndexSpan returns the span information for the index.\nfunc (f *File) IndexSpan(t *schema.Table, i *schema.Index) ResourceSpan {\n\treturn f.tableSpan(t).indexes[i.Name]\n}\n\n// ForeignKeySpan returns the span information for the foreign-key constraint.\nfunc (f *File) ForeignKeySpan(t *schema.Table, fk *schema.ForeignKey) ResourceSpan {\n\treturn f.tableSpan(t).forkeys[fk.Symbol]\n}\n\ntype (\n\t// schemaSpan holds the span structure of a schema.\n\tschemaSpan struct {\n\t\tstate  ResourceSpan\n\t\ttables map[string]*tableSpan\n\t}\n\t// schemaSpan holds the span structure of a table.\n\ttableSpan struct {\n\t\tstate   ResourceSpan\n\t\tcolumns map[string]ResourceSpan\n\t\tindexes map[string]ResourceSpan\n\t\tforkeys map[string]ResourceSpan\n\t}\n)\n\nfunc (f *File) loadSpans() {\n\tf.spans = make(map[string]*schemaSpan)\n\tfor _, sc := range f.Changes {\n\t\tfor _, c := range sc.Changes {\n\t\t\tswitch c := c.(type) {\n\t\t\tcase *schema.AddSchema:\n\t\t\t\tf.schemaSpan(c.S).state = SpanAdded\n\t\t\tcase *schema.DropSchema:\n\t\t\t\tf.schemaSpan(c.S).state |= SpanDropped\n\t\t\tcase *schema.AddTable:\n\t\t\t\tspan := f.tableSpan(c.T)\n\t\t\t\tspan.state = SpanAdded\n\t\t\t\tfor _, column := range c.T.Columns {\n\t\t\t\t\tspan.columns[column.Name] = SpanAdded\n\t\t\t\t}\n\t\t\t\tfor _, idx := range c.T.Indexes {\n\t\t\t\t\tspan.indexes[idx.Name] = SpanAdded\n\t\t\t\t}\n\t\t\t\tfor _, fk := range c.T.ForeignKeys {\n\t\t\t\t\tspan.forkeys[fk.Symbol] = SpanAdded\n\t\t\t\t}\n\t\t\tcase *schema.DropTable:\n\t\t\t\tf.tableSpan(c.T).state |= SpanDropped\n\t\t\tcase *schema.ModifyTable:\n\t\t\t\tspan := f.tableSpan(c.T)\n\t\t\t\tfor _, c1 := range c.Changes {\n\t\t\t\t\tswitch c1 := c1.(type) {\n\t\t\t\t\tcase *schema.AddColumn:\n\t\t\t\t\t\tspan.columns[c1.C.Name] = SpanAdded\n\t\t\t\t\tcase *schema.DropColumn:\n\t\t\t\t\t\tspan.columns[c1.C.Name] |= SpanDropped\n\t\t\t\t\tcase *schema.AddIndex:\n\t\t\t\t\t\tspan.indexes[c1.I.Name] = SpanAdded\n\t\t\t\t\tcase *schema.DropIndex:\n\t\t\t\t\t\tspan.indexes[c1.I.Name] |= SpanDropped\n\t\t\t\t\tcase *schema.AddForeignKey:\n\t\t\t\t\t\tspan.forkeys[c1.F.Symbol] = SpanAdded\n\t\t\t\t\tcase *schema.DropForeignKey:\n\t\t\t\t\t\tspan.forkeys[c1.F.Symbol] |= SpanDropped\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (f *File) schemaSpan(s *schema.Schema) *schemaSpan {\n\tif f.spans == nil {\n\t\tf.loadSpans()\n\t}\n\tif f.spans[s.Name] == nil {\n\t\tf.spans[s.Name] = &schemaSpan{tables: make(map[string]*tableSpan)}\n\t}\n\treturn f.spans[s.Name]\n}\n\nfunc (f *File) tableSpan(t *schema.Table) *tableSpan {\n\tspan := f.schemaSpan(t.Schema)\n\tif span.tables[t.Name] == nil {\n\t\tspan.tables[t.Name] = &tableSpan{\n\t\t\tcolumns: make(map[string]ResourceSpan),\n\t\t\tindexes: make(map[string]ResourceSpan),\n\t\t\tforkeys: make(map[string]ResourceSpan),\n\t\t}\n\t}\n\treturn f.spans[t.Schema.Name].tables[t.Name]\n}\n\n// codes registry\nvar codes sync.Map\n\n// Code stores the given code in the registry.\n// It protects from duplicate analyzers' codes.\nfunc Code(code string) string {\n\tif _, loaded := codes.LoadOrStore(code, struct{}{}); loaded {\n\t\tpanic(\"sqlcheck: Code called twice for \" + code)\n\t}\n\treturn code\n}\n\n// drivers specific analyzers.\nvar drivers sync.Map\n\n// Register allows drivers to register a constructor function for creating\n// analyzers from the given HCL resource.\nfunc Register(name string, f func(*schemahcl.Resource) ([]Analyzer, error)) {\n\tdrivers.Store(name, f)\n}\n\n// AnalyzerFor instantiates a new Analyzer from the given HCL resource\n// based on the registered constructor function.\nfunc AnalyzerFor(name string, r *schemahcl.Resource) ([]Analyzer, error) {\n\tf, ok := drivers.Load(name)\n\tif ok {\n\t\treturn f.(func(*schemahcl.Resource) ([]Analyzer, error))(r)\n\t}\n\treturn nil, nil\n}\n"
  },
  {
    "path": "sql/sqlclient/client.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlclient\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"sync\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\ntype (\n\t// Client provides the common functionalities for working with Atlas from different\n\t// applications (e.g. CLI and TF). Note, the Client is dialect specific and should\n\t// be instantiated using a call to Open.\n\tClient struct {\n\t\t// Name used when creating the client.\n\t\tName string\n\n\t\t// DB used for creating the client.\n\t\tDB *sql.DB\n\t\t// URL holds an enriched url.URL.\n\t\tURL *URL\n\n\t\t// A migration driver for the attached dialect.\n\t\tmigrate.Driver\n\t\t// Additional closers that can be closed at the\n\t\t// end of the client lifetime.\n\t\tclosers []io.Closer\n\n\t\t// Marshal and Evaluator functions for decoding\n\t\t// and encoding the schema documents.\n\t\tschemahcl.Marshaler\n\t\tschemahcl.Evaluator\n\n\t\t// Ephemeral indicates that the database we connect to is \"ephemeral\"\n\t\t// (e.g., a temporary running container). This can be set by the driver\n\t\t// that opens the client to signal to its consumers that there is no need\n\t\t// to guard against race conditions with other Atlas clients.\n\t\tEphemeral bool\n\n\t\t// Functions registered by the drivers and used for opening transactions and their clients.\n\t\topenDriver func(schema.ExecQuerier) (migrate.Driver, error)\n\t\topenTx     TxOpener\n\t\thooks      []*Hook\n\t}\n\n\t// TxClient is returned by calling Client.Tx. It behaves the same as Client,\n\t// but wraps all operations within a transaction.\n\tTxClient struct {\n\t\t*Client\n\n\t\t// The transaction this Client wraps.\n\t\tTx    *Tx\n\t\thooks []*Hook\n\t}\n\n\t// URL extends the standard url.URL with additional\n\t// connection information attached by the Opener (if any).\n\tURL struct {\n\t\t*url.URL\n\n\t\t// The DSN used for opening the connection.\n\t\tDSN string `json:\"-\"`\n\n\t\t// The Schema this client is connected to.\n\t\tSchema string\n\t}\n\n\t// Hook groups all possible hooks in\n\t// connection and transaction lifecycle.\n\tHook struct {\n\t\tConn struct {\n\t\t\tAfterOpen   func(context.Context, *Client) error\n\t\t\tBeforeClose func(*Client) error\n\t\t}\n\t\tTx struct {\n\t\t\tAfterBegin func(context.Context, *TxClient) error\n\t\t\tBeforeCommit,\n\t\t\tBeforeRollback func(*TxClient) error\n\t\t}\n\t}\n)\n\n// Tx returns a transactional client.\nfunc (c *Client) Tx(ctx context.Context, opts *sql.TxOptions) (*TxClient, error) {\n\tif c.openDriver == nil {\n\t\treturn nil, errors.New(\"sql/sqlclient: unexpected driver opener: <nil>\")\n\t}\n\tvar tx *Tx\n\tswitch {\n\tcase c.openTx != nil:\n\t\tttx, err := c.openTx(ctx, c.DB, opts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ttx = ttx\n\tdefault:\n\t\tttx, err := c.DB.BeginTx(ctx, opts)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sql/sqlclient: starting transaction: %w\", err)\n\t\t}\n\t\ttx = &Tx{Tx: ttx}\n\t}\n\tdrv, err := c.openDriver(tx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/sqlclient: opening atlas driver: %w\", err)\n\t}\n\tic := *c\n\tic.Driver = drv\n\ttc := &TxClient{Client: &ic, Tx: tx, hooks: c.hooks}\n\tif len(tc.hooks) > 0 {\n\t\tif err := tc.afterBegin(ctx); err != nil {\n\t\t\treturn nil, errors.Join(err, tx.Rollback())\n\t\t}\n\t}\n\treturn tc, nil\n}\n\n// Commit the transaction.\nfunc (c *TxClient) Commit() error {\n\treturn errors.Join(c.beforeCommit(), c.Tx.Commit())\n}\n\n// Rollback the transaction.\nfunc (c *TxClient) Rollback() error {\n\treturn errors.Join(c.beforeRollback(), c.Tx.Rollback())\n}\n\n// AddClosers adds list of closers to close at the end of the client lifetime.\nfunc (c *Client) AddClosers(closers ...io.Closer) {\n\tc.closers = append(c.closers, closers...)\n}\n\n// Close closes the underlying database connection and the migration\n// driver in case it implements the io.Closer interface.\nfunc (c *Client) Close() error {\n\terr := c.beforeClose()\n\tfor _, closer := range append(c.closers, c.DB) {\n\t\terr = errors.Join(err, closer.Close())\n\t}\n\treturn err\n}\n\ntype hookCtxKey struct{}\n\n// hookCtx marks the context as being in a hook.\nfunc hookCtx(ctx context.Context) context.Context {\n\tif ctx.Value(hookCtxKey{}) == nil {\n\t\treturn context.WithValue(ctx, hookCtxKey{}, true)\n\t}\n\treturn ctx\n}\n\n// afterOpen calls the AfterOpen hooks.\nfunc (c *Client) afterOpen(ctx context.Context) error {\n\tif ctx.Value(hookCtxKey{}) != nil {\n\t\treturn errors.New(\"sql/sqlclient: cannot open a connection inside a hook\")\n\t}\n\tfor _, h := range c.hooks {\n\t\tif f := h.Conn.AfterOpen; f != nil {\n\t\t\tif err := f(hookCtx(ctx), c); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// beforeClose calls the BeforeClose hooks.\nfunc (c *Client) beforeClose() error {\n\tfor _, h := range c.hooks {\n\t\tif f := h.Conn.BeforeClose; f != nil {\n\t\t\tif err := f(c); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// afterBegin calls the AfterBegin hooks.\nfunc (c *TxClient) afterBegin(ctx context.Context) error {\n\tif ctx.Value(hookCtxKey{}) != nil {\n\t\treturn errors.New(\"sql/sqlclient: cannot begin a transaction inside a hook\")\n\t}\n\tfor _, h := range c.hooks {\n\t\tif f := h.Tx.AfterBegin; f != nil {\n\t\t\tif err := f(hookCtx(ctx), c); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// beforeCommit calls the BeforeCommit hooks.\nfunc (c *TxClient) beforeCommit() error {\n\tfor _, h := range c.hooks {\n\t\tif f := h.Tx.BeforeCommit; f != nil {\n\t\t\tif err := f(c); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// beforeRollback calls the BeforeRollback hooks.\nfunc (c *TxClient) beforeRollback() error {\n\tfor _, h := range c.hooks {\n\t\tif f := h.Tx.BeforeRollback; f != nil {\n\t\t\tif err := f(c); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\ntype (\n\t// Opener opens a migration driver by the given URL.\n\tOpener interface {\n\t\tOpen(ctx context.Context, u *url.URL) (*Client, error)\n\t}\n\n\t// OpenerFunc allows using a function as an Opener.\n\tOpenerFunc func(context.Context, *url.URL) (*Client, error)\n\n\t// URLParser parses an url.URL into an enriched URL and attaches additional info to it.\n\tURLParser interface {\n\t\tParseURL(*url.URL) *URL\n\t}\n\n\t// URLParserFunc allows using a function as an URLParser.\n\tURLParserFunc func(*url.URL) *URL\n\n\t// SchemaChanger is implemented by a driver if it how to change the connection URL to represent another schema.\n\tSchemaChanger interface {\n\t\tChangeSchema(*url.URL, string) *url.URL\n\t}\n\n\tdriver struct {\n\t\tOpener\n\t\tname     string\n\t\tparser   URLParser\n\t\ttxOpener TxOpener\n\t}\n)\n\n// Open calls f(ctx, u).\nfunc (f OpenerFunc) Open(ctx context.Context, u *url.URL) (*Client, error) {\n\treturn f(ctx, u)\n}\n\n// ParseURL calls f(u).\nfunc (f URLParserFunc) ParseURL(u *url.URL) *URL {\n\treturn f(u)\n}\n\n// ParseURL is similar to url.Parse but returns errors without\n// the raw URL attached to avoid printing userinfo in errors.\nfunc ParseURL(s string) (*url.URL, error) {\n\tu, err := url.Parse(s)\n\tif err != nil {\n\t\tif err1 := (*url.Error)(nil); errors.As(err, &err1) {\n\t\t\terr = err1.Err\n\t\t}\n\t\treturn nil, err\n\t}\n\treturn u, nil\n}\n\nvar drivers sync.Map\n\ntype (\n\t// openOptions holds additional configuration values for opening a Client.\n\topenOptions struct {\n\t\tschema *string\n\t\thooks  []*Hook\n\t}\n\t// OpenOption allows to configure a openOptions using functional arguments.\n\tOpenOption func(*openOptions) error\n)\n\n// ErrUnsupported is returned if a registered driver does not support changing the schema.\nvar ErrUnsupported = errors.New(\"sql/sqlclient: driver does not support changing connected schema\")\n\n// Open opens an Atlas client by its provided url string.\nfunc Open(ctx context.Context, s string, opts ...OpenOption) (*Client, error) {\n\tu, err := ParseURL(s)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/sqlclient: parse open url: %w\", err)\n\t}\n\treturn OpenURL(ctx, u, opts...)\n}\n\n// HasDriver reports if there is any driver registered with the given scheme.\nfunc HasDriver(scheme string) bool {\n\t_, ok := drivers.Load(scheme)\n\treturn ok\n}\n\n// OpenURL opens an Atlas client by its provided url.URL.\nfunc OpenURL(ctx context.Context, u *url.URL, opts ...OpenOption) (*Client, error) {\n\tcfg := &openOptions{}\n\tfor _, opt := range opts {\n\t\tif err := opt(cfg); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif u.Scheme == \"\" {\n\t\treturn nil, errors.New(\"sql/sqlclient: missing driver. See: https://atlasgo.io/url\")\n\t}\n\tv, ok := drivers.Load(u.Scheme)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"sql/sqlclient: unknown driver %q. See: https://atlasgo.io/url\", u.Scheme)\n\t}\n\tdrv := v.(*driver)\n\t// If there is a schema given and the driver allows to change the schema for the url, do it.\n\tif cfg.schema != nil {\n\t\tsc, ok := drv.parser.(SchemaChanger)\n\t\tif !ok {\n\t\t\treturn nil, ErrUnsupported\n\t\t}\n\t\tu = sc.ChangeSchema(u, *cfg.schema)\n\t}\n\tclient, err := drv.Open(ctx, u)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif client.URL == nil {\n\t\tclient.URL = drv.parser.ParseURL(u)\n\t}\n\tif client.openTx == nil && drv.txOpener != nil {\n\t\tclient.openTx = drv.txOpener\n\t}\n\tif len(cfg.hooks) > 0 {\n\t\tclient.hooks = cfg.hooks\n\t\tif err := client.afterOpen(ctx); err != nil {\n\t\t\treturn nil, errors.Join(err, client.DB.Close())\n\t\t}\n\t}\n\treturn client, nil\n}\n\n// OpenSchema opens the connection to the given schema.\n// If the registered driver does not support this, ErrUnsupported is returned instead.\nfunc OpenSchema(s string) OpenOption {\n\treturn func(c *openOptions) error {\n\t\tc.schema = &s\n\t\treturn nil\n\t}\n}\n\n// OpenWithHooks returns an OpenOption that sets\n// the hooks for the client after opening.\nfunc OpenWithHooks(hks ...*Hook) OpenOption {\n\treturn func(c *openOptions) error {\n\t\tc.hooks = append(c.hooks, hks...)\n\t\treturn nil\n\t}\n}\n\ntype (\n\tregisterOptions struct {\n\t\topenDriver func(schema.ExecQuerier) (migrate.Driver, error)\n\t\ttxOpener   TxOpener\n\t\tparser     URLParser\n\t\tflavours   []string\n\t\tschemahcl.Marshaler\n\t\tschemahcl.Evaluator\n\t}\n\t// RegisterOption allows configuring the Opener\n\t// registration using functional options.\n\tRegisterOption func(*registerOptions)\n)\n\n// RegisterFlavours allows registering additional flavours\n// (i.e. names), accepted by Atlas to open clients.\nfunc RegisterFlavours(flavours ...string) RegisterOption {\n\treturn func(opts *registerOptions) {\n\t\topts.flavours = flavours\n\t}\n}\n\n// RegisterURLParser allows registering a function for parsing\n// the url.URL and attach additional info to the extended URL.\nfunc RegisterURLParser(p URLParser) RegisterOption {\n\treturn func(opts *registerOptions) {\n\t\topts.parser = p\n\t}\n}\n\n// RegisterCodec registers static codec for attaching into\n// the client after it is opened.\nfunc RegisterCodec(m schemahcl.Marshaler, e schemahcl.Evaluator) RegisterOption {\n\treturn func(opts *registerOptions) {\n\t\topts.Marshaler, opts.Evaluator = m, e\n\t}\n}\n\n// RegisterDriverOpener registers a func to create a migrate.Driver from a schema.ExecQuerier.\n// Registering this function is implicitly done when using DriverOpener.\n// The passed opener is used when creating a TxClient.\nfunc RegisterDriverOpener(open func(schema.ExecQuerier) (migrate.Driver, error)) RegisterOption {\n\treturn func(opts *registerOptions) {\n\t\topts.openDriver = open\n\t}\n}\n\n// DriverOpener is a helper Opener creator for sharing between all drivers.\nfunc DriverOpener(open func(schema.ExecQuerier) (migrate.Driver, error)) Opener {\n\treturn OpenerFunc(func(_ context.Context, u *url.URL) (*Client, error) {\n\t\tv, ok := drivers.Load(u.Scheme)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"sql/sqlclient: unexpected missing opener %q\", u.Scheme)\n\t\t}\n\t\tdrv := v.(*driver)\n\t\tur := drv.parser.ParseURL(u)\n\t\tdb, err := sql.Open(drv.name, ur.DSN)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmdr, err := open(db)\n\t\tif err != nil {\n\t\t\tif cerr := db.Close(); cerr != nil {\n\t\t\t\terr = fmt.Errorf(\"%w: %v\", err, cerr)\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &Client{\n\t\t\tName:       drv.name,\n\t\t\tDB:         db,\n\t\t\tURL:        ur,\n\t\t\tDriver:     mdr,\n\t\t\topenDriver: open,\n\t\t\topenTx:     drv.txOpener,\n\t\t}, nil\n\t})\n}\n\ntype (\n\t// Tx wraps sql.Tx with optional custom Commit and Rollback functions.\n\tTx struct {\n\t\t*sql.Tx\n\t\tCommitFn   func() error // override default commit behavior\n\t\tRollbackFn func() error // override default rollback behavior\n\t}\n\t// TxOpener opens a transaction with optional closer.\n\tTxOpener func(context.Context, *sql.DB, *sql.TxOptions) (*Tx, error)\n)\n\n// Commit the transaction.\nfunc (tx *Tx) Commit() error {\n\tfn := tx.CommitFn\n\tif fn == nil {\n\t\tfn = tx.Tx.Commit\n\t}\n\treturn fn()\n}\n\n// Rollback the transaction.\nfunc (tx *Tx) Rollback() error {\n\tfn := tx.RollbackFn\n\tif fn == nil {\n\t\tfn = tx.Tx.Rollback\n\t}\n\treturn fn()\n}\n\n// RegisterTxOpener allows registering a custom transaction opener with an optional close function.\nfunc RegisterTxOpener(open TxOpener) RegisterOption {\n\treturn func(opts *registerOptions) {\n\t\topts.txOpener = open\n\t}\n}\n\n// Register registers a client Opener (i.e. creator) with the given name.\nfunc Register(name string, opener Opener, opts ...RegisterOption) {\n\tif opener == nil {\n\t\tpanic(\"sql/sqlclient: Register opener is nil\")\n\t}\n\topt := &registerOptions{\n\t\t// Default URL parser uses the URL as the DSN.\n\t\tparser: URLParserFunc(func(u *url.URL) *URL { return &URL{URL: u, DSN: u.String()} }),\n\t}\n\tfor i := range opts {\n\t\topts[i](opt)\n\t}\n\tif opt.Marshaler != nil && opt.Evaluator != nil {\n\t\tf := opener\n\t\topener = OpenerFunc(func(ctx context.Context, u *url.URL) (*Client, error) {\n\t\t\tc, err := f.Open(ctx, u)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tc.Marshaler, c.Evaluator = opt.Marshaler, opt.Evaluator\n\t\t\treturn c, nil\n\t\t})\n\t}\n\t// If there was a driver opener registered by a call to RegisterDriverOpener, it has precedence.\n\tif opt.openDriver != nil {\n\t\tf := opener\n\t\topener = OpenerFunc(func(ctx context.Context, u *url.URL) (*Client, error) {\n\t\t\tc, err := f.Open(ctx, u)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tc.openDriver = opt.openDriver\n\t\t\treturn c, err\n\t\t})\n\t}\n\tdrv := &driver{Opener: opener, name: name, parser: opt.parser, txOpener: opt.txOpener}\n\tfor _, f := range append(opt.flavours, name) {\n\t\tif _, ok := drivers.Load(f); ok {\n\t\t\tpanic(\"sql/sqlclient: Register called twice for \" + f)\n\t\t}\n\t\tdrivers.Store(f, drv)\n\t}\n}\n"
  },
  {
    "path": "sql/sqlclient/client_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlclient_test\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"ariga.io/atlas/sql/sqlclient\"\n)\n\nfunc TestRegisterOpen(t *testing.T) {\n\tc := &sqlclient.Client{}\n\tsqlclient.Register(\n\t\t\"mysql\",\n\t\tsqlclient.OpenerFunc(func(context.Context, *url.URL) (*sqlclient.Client, error) {\n\t\t\treturn c, nil\n\t\t}),\n\t\tsqlclient.RegisterFlavours(\"maria\"),\n\t\tsqlclient.RegisterURLParser(sqlclient.URLParserFunc(func(u *url.URL) *sqlclient.URL {\n\t\t\treturn &sqlclient.URL{URL: u, DSN: \"dsn\", Schema: \"schema\"}\n\t\t})),\n\t)\n\trequire.PanicsWithValue(\n\t\tt,\n\t\t\"sql/sqlclient: Register opener is nil\",\n\t\tfunc() { sqlclient.Register(\"mysql\", nil) },\n\t)\n\trequire.PanicsWithValue(\n\t\tt,\n\t\t\"sql/sqlclient: Register called twice for mysql\",\n\t\tfunc() {\n\t\t\tsqlclient.Register(\"mysql\", sqlclient.OpenerFunc(func(context.Context, *url.URL) (*sqlclient.Client, error) {\n\t\t\t\treturn c, nil\n\t\t\t}))\n\t\t},\n\t)\n\tc1, err := sqlclient.Open(context.Background(), \"mysql://:3306\")\n\trequire.NoError(t, err)\n\trequire.True(t, c == c1)\n\trequire.Equal(t, \"dsn\", c.URL.DSN)\n\trequire.Equal(t, \"schema\", c.URL.Schema)\n\n\tc1, err = sqlclient.Open(context.Background(), \"maria://:3306\")\n\trequire.NoError(t, err)\n\trequire.True(t, c == c1)\n\trequire.Equal(t, \"dsn\", c.URL.DSN)\n\trequire.Equal(t, \"schema\", c.URL.Schema)\n\n\tc1, err = sqlclient.Open(context.Background(), \"postgres://:3306\")\n\trequire.EqualError(t, err, `sql/sqlclient: unknown driver \"postgres\". See: https://atlasgo.io/url`)\n}\n\nfunc TestOpen_Errors(t *testing.T) {\n\tc, err := sqlclient.Open(context.Background(), \"missing\")\n\trequire.EqualError(t, err, `sql/sqlclient: missing driver. See: https://atlasgo.io/url`)\n\trequire.Nil(t, c)\n\tc, err = sqlclient.Open(context.Background(), \"unknown://\")\n\trequire.EqualError(t, err, `sql/sqlclient: unknown driver \"unknown\". See: https://atlasgo.io/url`)\n\trequire.Nil(t, c)\n\n\t// URLs are not attached to errors.\n\t_, err = sqlclient.Open(context.Background(), \" postgres://user:pass:3306/\")\n\trequire.EqualError(t, err, \"sql/sqlclient: parse open url: first path segment in URL cannot contain colon\")\n\t_, err = sqlclient.Open(context.Background(), \"scheme://hello world\")\n\trequire.EqualError(t, err, `sql/sqlclient: parse open url: invalid character \" \" in host name`)\n}\n\nfunc TestParseURL(t *testing.T) {\n\t_, err := sqlclient.ParseURL(\"boring ://\")\n\trequire.EqualError(t, err, \"first path segment in URL cannot contain colon\")\n\t_, err = sqlclient.ParseURL(\"\\bboring://foo.com:3000\")\n\trequire.EqualError(t, err, \"net/url: invalid control character in URL\")\n\t_, err = sqlclient.ParseURL(\"boring:// : @foo.com:3000\")\n\trequire.EqualError(t, err, \"net/url: invalid userinfo\")\n}\n\nfunc TestClient_AddClosers(t *testing.T) {\n\tvar (\n\t\ti int\n\t\tc = &sqlclient.Client{DB: sql.OpenDB(nil)}\n\t\tf = closerFunc(func() error { i++; return nil })\n\t)\n\tc.AddClosers(f, f, f)\n\trequire.NoError(t, c.Close())\n\trequire.Equal(t, 3, i)\n}\n\ntype closerFunc func() error\n\nfunc (f closerFunc) Close() error { return f() }\n\nfunc TestClient_Tx(t *testing.T) {\n\tdb, mock, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tdefer db.Close()\n\n\tconst stmt = \"create database `test`\"\n\tmock.ExpectBegin()\n\tmock.ExpectExec(stmt).WillReturnResult(sqlmock.NewResult(0, 1))\n\tmock.ExpectCommit()\n\tmock.ExpectBegin()\n\tmock.ExpectExec(stmt).WillReturnResult(sqlmock.NewResult(0, 1))\n\tmock.ExpectRollback()\n\n\tvar cC, rC bool\n\tsqlclient.Register(\n\t\t\"tx\",\n\t\tsqlclient.OpenerFunc(func(context.Context, *url.URL) (*sqlclient.Client, error) {\n\t\t\treturn &sqlclient.Client{Name: \"tx\", DB: db, Driver: &mockDriver{db: db}}, nil\n\t\t}),\n\t\tsqlclient.RegisterDriverOpener(func(db schema.ExecQuerier) (migrate.Driver, error) {\n\t\t\treturn &mockDriver{db: db}, nil\n\t\t}),\n\t\tsqlclient.RegisterTxOpener(func(ctx context.Context, db *sql.DB, opts *sql.TxOptions) (*sqlclient.Tx, error) {\n\t\t\ttx, err := db.BeginTx(ctx, opts)\n\t\t\trequire.NoError(t, err)\n\t\t\treturn &sqlclient.Tx{\n\t\t\t\tTx: tx,\n\t\t\t\tCommitFn: func() error {\n\t\t\t\t\tcC = true\n\t\t\t\t\treturn tx.Commit()\n\t\t\t\t},\n\t\t\t\tRollbackFn: func() error {\n\t\t\t\t\trC = true\n\t\t\t\t\treturn tx.Rollback()\n\t\t\t\t},\n\t\t\t}, nil\n\t\t}),\n\t)\n\n\tc, err := sqlclient.Open(context.Background(), \"tx://\")\n\trequire.NoError(t, err)\n\n\t// Commit works.\n\ttx, err := c.Tx(context.Background(), nil)\n\trequire.NoError(t, err)\n\t_, err = tx.ExecContext(context.Background(), stmt)\n\trequire.NoError(t, err)\n\trequire.NoError(t, tx.Commit())\n\trequire.True(t, cC)\n\n\t// Rollback works as well.\n\ttx, err = c.Tx(context.Background(), nil)\n\trequire.NoError(t, err)\n\t_, err = tx.ExecContext(context.Background(), stmt)\n\trequire.NoError(t, err)\n\trequire.NoError(t, tx.Rollback())\n\trequire.True(t, rC)\n\n\trequire.NoError(t, mock.ExpectationsWereMet())\n}\n\ntype mockDriver struct {\n\tmigrate.Driver\n\tdb schema.ExecQuerier\n}\n\nfunc (m *mockDriver) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) {\n\treturn m.db.ExecContext(ctx, query, args...)\n}\n\nfunc TestClientHooks(t *testing.T) {\n\tdb, mock, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tsqlclient.Register(\n\t\t\"hook\",\n\t\tsqlclient.OpenerFunc(func(context.Context, *url.URL) (*sqlclient.Client, error) {\n\t\t\treturn &sqlclient.Client{Name: \"tx\", DB: db, Driver: &mockDriver{db: db}}, nil\n\t\t}),\n\t\tsqlclient.RegisterDriverOpener(func(db schema.ExecQuerier) (migrate.Driver, error) {\n\t\t\treturn &mockDriver{db: db}, nil\n\t\t}),\n\t)\n\tvar (\n\t\tcalls [5]int\n\t\thk    = &sqlclient.Hook{}\n\t)\n\thk.Conn.AfterOpen = func(context.Context, *sqlclient.Client) error {\n\t\tcalls[0]++\n\t\treturn nil\n\t}\n\thk.Conn.BeforeClose = func(*sqlclient.Client) error {\n\t\tcalls[1]++\n\t\treturn nil\n\t}\n\thk.Tx.AfterBegin = func(context.Context, *sqlclient.TxClient) error {\n\t\tcalls[2]++\n\t\treturn nil\n\t}\n\thk.Tx.BeforeCommit = func(*sqlclient.TxClient) error {\n\t\tcalls[3]++\n\t\treturn nil\n\t}\n\thk.Tx.BeforeRollback = func(*sqlclient.TxClient) error {\n\t\tcalls[4]++\n\t\treturn nil\n\t}\n\tmock.ExpectClose()\n\toc, err := sqlclient.Open(context.Background(), \"hook://\", sqlclient.OpenWithHooks(hk))\n\trequire.NoError(t, err)\n\trequire.NoError(t, oc.Close())\n\trequire.Equal(t, [5]int{1, 1, 0, 0, 0}, calls)\n\trequire.NoError(t, mock.ExpectationsWereMet())\n\n\tdb, mock, err = sqlmock.New()\n\trequire.NoError(t, err)\n\tmock.ExpectBegin()\n\tmock.ExpectCommit()\n\tmock.ExpectClose()\n\toc, err = sqlclient.Open(context.Background(), \"hook://\", sqlclient.OpenWithHooks(hk))\n\trequire.NoError(t, err)\n\ttc, err := oc.Tx(context.Background(), nil)\n\trequire.NoError(t, err)\n\trequire.NoError(t, tc.Commit())\n\trequire.NoError(t, oc.Close())\n\trequire.Equal(t, [5]int{2, 2, 1, 1, 0}, calls)\n\trequire.NoError(t, mock.ExpectationsWereMet())\n\n\tdb, mock, err = sqlmock.New()\n\trequire.NoError(t, err)\n\tmock.ExpectBegin()\n\tmock.ExpectRollback()\n\tmock.ExpectClose()\n\toc, err = sqlclient.Open(context.Background(), \"hook://\", sqlclient.OpenWithHooks(hk))\n\trequire.NoError(t, err)\n\ttc, err = oc.Tx(context.Background(), nil)\n\trequire.NoError(t, err)\n\trequire.NoError(t, tc.Rollback())\n\trequire.NoError(t, oc.Close())\n\trequire.Equal(t, [5]int{3, 3, 2, 1, 1}, calls)\n\trequire.NoError(t, mock.ExpectationsWereMet())\n\n\t// Open hook failed.\n\thk.Conn.AfterOpen = func(context.Context, *sqlclient.Client) error {\n\t\tcalls[0]++\n\t\treturn errors.New(\"open failed\")\n\t}\n\tdb, mock, err = sqlmock.New()\n\trequire.NoError(t, err)\n\tmock.ExpectClose()\n\toc, err = sqlclient.Open(context.Background(), \"hook://\", sqlclient.OpenWithHooks(hk))\n\trequire.EqualError(t, err, \"open failed\")\n\trequire.Equal(t, [5]int{4, 3, 2, 1, 1}, calls, \"close hooks should not be called\")\n\trequire.NoError(t, mock.ExpectationsWereMet())\n\n\t// After begin hook failed.\n\thk.Conn.AfterOpen = func(context.Context, *sqlclient.Client) error {\n\t\tcalls[0]++\n\t\treturn nil\n\t}\n\thk.Tx.AfterBegin = func(context.Context, *sqlclient.TxClient) error {\n\t\tcalls[2]++\n\t\treturn errors.New(\"after begin failed\")\n\t}\n\tdb, mock, err = sqlmock.New()\n\trequire.NoError(t, err)\n\tmock.ExpectBegin()\n\tmock.ExpectRollback()\n\tmock.ExpectClose()\n\toc, err = sqlclient.Open(context.Background(), \"hook://\", sqlclient.OpenWithHooks(hk))\n\trequire.NoError(t, err)\n\ttc, err = oc.Tx(context.Background(), nil)\n\trequire.EqualError(t, err, \"after begin failed\")\n\trequire.NoError(t, oc.Close())\n\trequire.Equal(t, [5]int{5, 4, 3, 1, 1}, calls, \"rollback hooks should not be called\")\n}\n"
  },
  {
    "path": "sql/sqlite/convert.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// FormatType converts types to one format. A lowered format.\n// This is due to SQLite flexibility to allow any data types\n// and use a set of rules to define the type affinity.\n// See: https://www.sqlite.org/datatype3.html\nfunc FormatType(t schema.Type) (string, error) {\n\tvar f string\n\tswitch t := t.(type) {\n\tcase *schema.BoolType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.BinaryType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.EnumType:\n\t\tf = t.T\n\tcase *schema.IntegerType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.StringType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.TimeType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.FloatType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.DecimalType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.JSONType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.SpatialType:\n\t\tf = strings.ToLower(t.T)\n\tcase *schema.UUIDType:\n\t\tf = strings.ToLower(t.T)\n\tcase *UserDefinedType:\n\t\tf = t.T\n\tcase *schema.UnsupportedType:\n\t\treturn \"\", fmt.Errorf(\"sqlite: unsupported type: %q\", t.T)\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"sqlite: invalid schema type: %T\", t)\n\t}\n\treturn f, nil\n}\n\n// ParseType returns the schema.Type value represented by the given raw type.\n// It is expected to be one of the types in https://www.sqlite.org/datatypes.html,\n// or some of the common types used by ORMs like Ent.\nfunc ParseType(c string) (schema.Type, error) {\n\t// A datatype may be zero or more names.\n\tif c == \"\" {\n\t\treturn &schema.BinaryType{T: \"blob\"}, nil\n\t}\n\tparts := columnParts(c)\n\tswitch t := parts[0]; t {\n\tcase \"bool\", \"boolean\":\n\t\treturn &schema.BoolType{T: t}, nil\n\tcase \"blob\":\n\t\treturn &schema.BinaryType{T: t}, nil\n\tcase \"int2\", \"int8\", \"int\", \"uint64\", \"integer\", \"tinyint\", \"smallint\", \"mediumint\", \"bigint\", \"unsigned big int\":\n\t\t// All integer types have the same \"type affinity\".\n\t\treturn &schema.IntegerType{T: t}, nil\n\tcase \"real\", \"double\", \"double precision\", \"float\":\n\t\treturn &schema.FloatType{T: t}, nil\n\tcase \"numeric\", \"decimal\":\n\t\tct := &schema.DecimalType{T: t}\n\t\tif len(parts) > 1 {\n\t\t\tp, err := strconv.ParseInt(parts[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse precision %q\", parts[1])\n\t\t\t}\n\t\t\tct.Precision = int(p)\n\t\t}\n\t\tif len(parts) > 2 {\n\t\t\ts, err := strconv.ParseInt(parts[2], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse scale %q\", parts[1])\n\t\t\t}\n\t\t\tct.Scale = int(s)\n\t\t}\n\t\treturn ct, nil\n\tcase \"char\", \"character\", \"varchar\", \"varying character\", \"nchar\", \"native character\", \"nvarchar\", \"text\", \"clob\":\n\t\tct := &schema.StringType{T: t}\n\t\tif len(parts) > 1 {\n\t\t\tp, err := strconv.ParseInt(parts[1], 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse size %q\", parts[1])\n\t\t\t}\n\t\t\tct.Size = int(p)\n\t\t}\n\t\treturn ct, nil\n\tcase \"json\", \"jsonb\":\n\t\treturn &schema.JSONType{T: t}, nil\n\tcase \"date\", \"datetime\", \"time\", \"timestamp\":\n\t\treturn &schema.TimeType{T: t}, nil\n\tcase \"uuid\":\n\t\treturn &schema.UUIDType{T: t}, nil\n\tdefault:\n\t\treturn &UserDefinedType{T: c}, nil\n\t}\n}\n"
  },
  {
    "path": "sql/sqlite/diff.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// DefaultDiff provides basic diffing capabilities for MySQL dialects.\n// Note, it is recommended to call Open, create a new Driver and use its\n// Differ when a database connection is available.\nvar DefaultDiff schema.Differ = &sqlx.Diff{DiffDriver: &diff{}}\n\n// A diff provides a SQLite implementation for sqlx.DiffDriver.\ntype diff struct{}\n\n// SchemaAttrDiff returns a changeset for migrating schema attributes from one state to the other.\nfunc (*diff) SchemaAttrDiff(_, _ *schema.Schema) []schema.Change {\n\t// No special schema attribute diffing for SQLite.\n\treturn nil\n}\n\n// RealmObjectDiff returns a changeset for migrating realm (database) objects\n// from one state to the other. For example, adding extensions or users.\nfunc (*diff) RealmObjectDiff(_, _ *schema.Realm) ([]schema.Change, error) {\n\treturn nil, nil\n}\n\n// SchemaObjectDiff returns a changeset for migrating schema objects from\n// one state to the other.\nfunc (*diff) SchemaObjectDiff(_, _ *schema.Schema, _ *schema.DiffOptions) ([]schema.Change, error) {\n\treturn nil, nil\n}\n\n// TableAttrDiff returns a changeset for migrating table attributes from one state to the other.\nfunc (d *diff) TableAttrDiff(from, to *schema.Table, opts *schema.DiffOptions) ([]schema.Change, error) {\n\tvar changes []schema.Change\n\tfor _, a := range []schema.Attr{&WithoutRowID{}, &Strict{}} {\n\t\tswitch {\n\t\tcase sqlx.Has(from.Attrs, a) && !sqlx.Has(to.Attrs, a):\n\t\t\tchanges = append(changes, &schema.DropAttr{\n\t\t\t\tA: a,\n\t\t\t})\n\t\tcase !sqlx.Has(from.Attrs, a) && sqlx.Has(to.Attrs, a):\n\t\t\tchanges = append(changes, &schema.AddAttr{\n\t\t\t\tA: a,\n\t\t\t})\n\t\t}\n\t}\n\treturn append(changes, sqlx.CheckDiffMode(from, to, opts.Mode)...), nil\n}\n\nfunc (*diff) ViewAttrChanges(_, _ *schema.View) []schema.Change {\n\treturn nil // Not implemented.\n}\n\n// ColumnChange returns the schema changes (if any) for migrating one column to the other.\n// Note that column comments are ignored as SQLite does not support it.\nfunc (d *diff) ColumnChange(_ *schema.Table, from, to *schema.Column, _ *schema.DiffOptions) (schema.Change, error) {\n\tvar change schema.ChangeKind\n\tif from.Type.Null != to.Type.Null {\n\t\tchange |= schema.ChangeNull\n\t}\n\tchanged, err := d.typeChanged(from, to)\n\tif err != nil {\n\t\treturn sqlx.NoChange, err\n\t}\n\tif changed {\n\t\tchange |= schema.ChangeType\n\t}\n\tif changed := d.defaultChanged(from, to); changed {\n\t\tchange |= schema.ChangeDefault\n\t}\n\tif d.generatedChanged(from, to) {\n\t\tchange |= schema.ChangeGenerated\n\t}\n\tif change.Is(schema.NoChange) {\n\t\treturn sqlx.NoChange, nil\n\t}\n\treturn &schema.ModifyColumn{\n\t\tChange: change,\n\t\tFrom:   from,\n\t\tTo:     to,\n\t}, nil\n}\n\n// typeChanged reports if the column type was changed.\nfunc (d *diff) typeChanged(from, to *schema.Column) (bool, error) {\n\tfromT, toT := from.Type.Type, to.Type.Type\n\tif fromT == nil || toT == nil {\n\t\treturn false, fmt.Errorf(\"sqlite: missing type information for column %q\", from.Name)\n\t}\n\tif u1, ok := fromT.(*UserDefinedType); ok {\n\t\tu2, ok := toT.(*UserDefinedType)\n\t\treturn !ok || u1.T != u2.T, nil\n\t}\n\t// Types are mismatched if they do not have the same \"type affinity\".\n\treturn reflect.TypeOf(fromT) != reflect.TypeOf(toT), nil\n}\n\n// defaultChanged reports if the default value of a column was changed.\nfunc (d *diff) defaultChanged(from, to *schema.Column) bool {\n\td1, ok1 := sqlx.DefaultValue(from)\n\td2, ok2 := sqlx.DefaultValue(to)\n\tif ok1 != ok2 {\n\t\treturn true\n\t}\n\tif d1 == d2 {\n\t\treturn false\n\t}\n\tx1, err1 := sqlx.Unquote(d1)\n\tx2, err2 := sqlx.Unquote(d2)\n\treturn err1 != nil || err2 != nil || x1 != x2\n}\n\n// generatedChanged reports if the generated expression of a column was changed.\nfunc (*diff) generatedChanged(from, to *schema.Column) bool {\n\tvar (\n\t\tfromX, toX     schema.GeneratedExpr\n\t\tfromHas, toHas = sqlx.Has(from.Attrs, &fromX), sqlx.Has(to.Attrs, &toX)\n\t)\n\treturn fromHas != toHas || fromHas && (sqlx.MayWrap(fromX.Expr) != sqlx.MayWrap(toX.Expr) || storedOrVirtual(fromX.Type) != storedOrVirtual(toX.Type))\n}\n\n// IsGeneratedIndexName reports if the index name was generated by the database.\n// See: https://github.com/sqlite/sqlite/blob/e937df8/src/build.c#L3583.\nfunc (d *diff) IsGeneratedIndexName(t *schema.Table, idx *schema.Index) bool {\n\tp := fmt.Sprintf(\"sqlite_autoindex_%s_\", t.Name)\n\tif !strings.HasPrefix(idx.Name, p) {\n\t\treturn false\n\t}\n\ti, err := strconv.ParseInt(strings.TrimPrefix(idx.Name, p), 10, 64)\n\treturn err == nil && i > 0\n}\n\n// FindGeneratedIndex finds the table index that represents the generated index.\n// This is useful because unlike MySQL/PostgreSQL, SQLite does not allow creating\n// the generated indexes with their internal names. Therefore, they are renamed in\n// normalization phase. See migrate.go#normalizeIdxName for more details.\nfunc (d *diff) FindGeneratedIndex(t *schema.Table, idx *schema.Index) (*schema.Index, bool) {\n\tnr := schema.NewIndex(idx.Name)\n\tif normalizeIdxName(nr, t) != nil {\n\t\treturn nil, false\n\t}\n\treturn t.Index(nr.Name)\n}\n\n// IndexAttrChanged reports if the index attributes were changed.\nfunc (*diff) IndexAttrChanged(from, to []schema.Attr) bool {\n\tvar p1, p2 IndexPredicate\n\treturn sqlx.Has(from, &p1) != sqlx.Has(to, &p2) || (p1.P != p2.P && p1.P != sqlx.MayWrap(p2.P))\n}\n\n// IndexPartAttrChanged reports if the index-part attributes were changed.\nfunc (*diff) IndexPartAttrChanged(_, _ *schema.Index, _ int) bool {\n\treturn false\n}\n\n// ReferenceChanged reports if the foreign key referential action was changed.\nfunc (*diff) ReferenceChanged(from, to schema.ReferenceOption) bool {\n\t// According to SQLite, if an action is not explicitly\n\t// specified, it defaults to \"NO ACTION\".\n\tif from == \"\" {\n\t\tfrom = schema.NoAction\n\t}\n\tif to == \"\" {\n\t\tto = schema.NoAction\n\t}\n\treturn from != to\n}\n\n// ForeignKeyAttrChanged reports if any of the foreign-key attributes were changed.\nfunc (*diff) ForeignKeyAttrChanged(_, _ []schema.Attr) bool {\n\treturn false\n}\n\n// Normalize implements the sqlx.Normalizer interface.\nfunc (d *diff) Normalize(from, to *schema.Table, _ *schema.DiffOptions) error {\n\tused := make([]bool, len(to.ForeignKeys))\n\t// In SQLite, there is no easy way to get the foreign-key constraint\n\t// name, except for parsing the CREATE statement. Therefore, we check\n\t// if there is a foreign-key with identical properties.\n\tfor _, fk1 := range from.ForeignKeys {\n\t\tfor i, fk2 := range to.ForeignKeys {\n\t\t\tif used[i] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif fk2.Symbol == fk1.Symbol && !sqlx.IsUint(fk1.Symbol) || sameFK(fk1, fk2) {\n\t\t\t\tfk1.Symbol = fk2.Symbol\n\t\t\t\tused[i] = true\n\t\t\t}\n\t\t}\n\t}\n\t// Normalize names of indexes generated by UNIQUE constraints before\n\t// comparing. See the normalizeIdxName function for details.\n\tfor _, idx := range to.Indexes {\n\t\tif err := normalizeIdxName(idx, to); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc sameFK(fk1, fk2 *schema.ForeignKey) bool {\n\tif fk1.Table.Name != fk2.Table.Name || fk1.RefTable.Name != fk2.RefTable.Name ||\n\t\tlen(fk1.Columns) != len(fk2.Columns) || len(fk1.RefColumns) != len(fk2.RefColumns) {\n\t\treturn false\n\t}\n\tfor i, c1 := range fk1.Columns {\n\t\tif c1.Name != fk2.Columns[i].Name {\n\t\t\treturn false\n\t\t}\n\t}\n\tfor i, c1 := range fk1.RefColumns {\n\t\tif c1.Name != fk2.RefColumns[i].Name {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "sql/sqlite/diff_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDiff_TableDiff(t *testing.T) {\n\ttype testcase struct {\n\t\tname        string\n\t\tfrom, to    *schema.Table\n\t\twantChanges []schema.Change\n\t\twantErr     bool\n\t}\n\ttests := []testcase{\n\t\t{\n\t\t\tname: \"no changes\",\n\t\t\tfrom: &schema.Table{Name: \"users\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\tto:   &schema.Table{Name: \"users\"},\n\t\t},\n\t\t{\n\t\t\tname: \"add attrs\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Schema: &schema.Schema{Name: \"public\"}},\n\t\t\tto:   &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&WithoutRowID{}, &Strict{}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.AddAttr{\n\t\t\t\t\tA: &WithoutRowID{},\n\t\t\t\t},\n\t\t\t\t&schema.AddAttr{\n\t\t\t\t\tA: &Strict{},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"drop attrs\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&WithoutRowID{}, &Strict{}}},\n\t\t\tto:   &schema.Table{Name: \"t1\"},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.DropAttr{\n\t\t\t\t\tA: &WithoutRowID{},\n\t\t\t\t},\n\t\t\t\t&schema.DropAttr{\n\t\t\t\t\tA: &Strict{},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"add check\",\n\t\t\tfrom: &schema.Table{Name: \"t1\"},\n\t\t\tto:   &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&schema.Check{Name: \"t1_c1_check\", Expr: \"(c1 > 1)\"}}},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.AddCheck{\n\t\t\t\t\tC: &schema.Check{Name: \"t1_c1_check\", Expr: \"(c1 > 1)\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"drop check\",\n\t\t\tfrom: &schema.Table{Name: \"t1\", Attrs: []schema.Attr{&schema.Check{Name: \"t1_c1_check\", Expr: \"(c1 > 1)\"}}},\n\t\t\tto:   &schema.Table{Name: \"t1\"},\n\t\t\twantChanges: []schema.Change{\n\t\t\t\t&schema.DropCheck{\n\t\t\t\t\tC: &schema.Check{Name: \"t1_c1_check\", Expr: \"(c1 > 1)\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"find check by expr\",\n\t\t\tfrom: &schema.Table{\n\t\t\t\tName: \"t1\",\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Check{Name: \"t1_c1_check\", Expr: \"(c1 > 1)\"},\n\t\t\t\t\t&schema.Check{Expr: \"(d1 > 1)\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\tto: &schema.Table{\n\t\t\t\tName: \"t1\",\n\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t&schema.Check{Expr: \"(c1 > 1)\"},\n\t\t\t\t\t&schema.Check{Name: \"add_name_to_check\", Expr: \"(d1 > 1)\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}},\n\t\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"int8\", Type: &schema.IntegerType{T: \"int8\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tto = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:    \"c1\",\n\t\t\t\t\t\t\tType:    &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}, Null: true},\n\t\t\t\t\t\t\tDefault: &schema.RawExpr{X: \"{}\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"columns\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\tFrom:   from.Columns[0],\n\t\t\t\t\t\tTo:     to.Columns[0],\n\t\t\t\t\t\tChange: schema.ChangeNull | schema.ChangeDefault,\n\t\t\t\t\t},\n\t\t\t\t\t&schema.DropColumn{C: from.Columns[1]},\n\t\t\t\t\t&schema.AddColumn{C: to.Columns[1]},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\ts    = schema.New(\"public\")\n\t\t\t\tfrom = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(s).\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\"),\n\t\t\t\t\t\tschema.NewIntColumn(\"c2\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\tschema.NewIntColumn(\"c3\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\"}),\n\t\t\t\t\t\tschema.NewIntColumn(\"c4\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"VIRTUAL\"}),\n\t\t\t\t\t)\n\t\t\t\tto = schema.NewTable(\"t1\").\n\t\t\t\t\tSetSchema(s).\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t// Add generated expression.\n\t\t\t\t\t\tschema.NewIntColumn(\"c1\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\t// Drop generated expression.\n\t\t\t\t\t\tschema.NewIntColumn(\"c2\", \"int\"),\n\t\t\t\t\t\t// Modify generated expression.\n\t\t\t\t\t\tschema.NewIntColumn(\"c3\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"2\"}),\n\t\t\t\t\t\t// No change.\n\t\t\t\t\t\tschema.NewIntColumn(\"c4\", \"int\").\n\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\"}),\n\t\t\t\t\t)\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"modify column generated\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyColumn{From: from.Columns[0], To: to.Columns[0], Change: schema.ChangeGenerated},\n\t\t\t\t\t&schema.ModifyColumn{From: from.Columns[1], To: to.Columns[1], Change: schema.ChangeGenerated},\n\t\t\t\t\t&schema.ModifyColumn{From: from.Columns[2], To: to.Columns[2], Change: schema.ChangeGenerated},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tfrom = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}},\n\t\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"int8\", Type: &schema.IntegerType{T: \"int8\"}}},\n\t\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tto = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Raw: \"json\", Type: &schema.JSONType{T: \"json\"}}},\n\t\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Raw: \"int8\", Type: &schema.IntegerType{T: \"int8\"}}},\n\t\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t)\n\t\t\tfrom.Indexes = []*schema.Index{\n\t\t\t\t{Name: \"c1_index\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[0]}}},\n\t\t\t\t{Name: \"c2_unique\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}},\n\t\t\t\t{Name: \"c3_predicate\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}},\n\t\t\t\t{Name: \"c3_desc\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: to.Columns[1]}}},\n\t\t\t\t{Name: \"c4_predicate\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexPredicate{P: \"(c4 <> NULL)\"}}},\n\t\t\t}\n\t\t\tto.Indexes = []*schema.Index{\n\t\t\t\t{Name: \"c1_index\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[0]}}},\n\t\t\t\t{Name: \"c3_unique\", Unique: true, Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: to.Columns[1]}}},\n\t\t\t\t{Name: \"c3_predicate\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexPredicate{P: \"c3 <> NULL\"}}},\n\t\t\t\t{Name: \"c3_desc\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, Desc: true, C: to.Columns[1]}}},\n\t\t\t\t{Name: \"c4_predicate\", Table: from, Parts: []*schema.IndexPart{{SeqNo: 1, C: from.Columns[1]}}, Attrs: []schema.Attr{&IndexPredicate{P: \"c4 <> NULL\"}}},\n\t\t\t}\n\t\t\treturn testcase{\n\t\t\t\tname: \"indexes\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[0], To: to.Indexes[0], Change: schema.ChangeUnique},\n\t\t\t\t\t&schema.DropIndex{I: from.Indexes[1]},\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[2], To: to.Indexes[2], Change: schema.ChangeAttr},\n\t\t\t\t\t&schema.ModifyIndex{From: from.Indexes[3], To: to.Indexes[3], Change: schema.ChangeParts},\n\t\t\t\t\t&schema.AddIndex{I: to.Indexes[1]},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tfrom := schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\tAddColumns(schema.NewStringColumn(\"id\", \"varchar\"), schema.NewBoolColumn(\"active\", \"bool\"))\n\t\t\tfrom.SetPrimaryKey(schema.NewPrimaryKey(from.Columns...))\n\t\t\tto := schema.NewTable(\"t1\").\n\t\t\t\tSetSchema(schema.New(\"test\")).\n\t\t\t\tAddColumns(schema.NewStringColumn(\"id\", \"varchar\"), schema.NewBoolColumn(\"active\", \"bool\"))\n\t\t\tto.SetPrimaryKey(\n\t\t\t\tschema.NewPrimaryKey(from.Columns...).\n\t\t\t\t\tAddAttrs(&IndexPredicate{P: \"active\"}),\n\t\t\t)\n\t\t\treturn testcase{\n\t\t\t\tname: \"modify primary-key\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyPrimaryKey{\n\t\t\t\t\t\tFrom:   from.PrimaryKey,\n\t\t\t\t\t\tTo:     to.PrimaryKey,\n\t\t\t\t\t\tChange: schema.ChangeAttr,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t\tfunc() testcase {\n\t\t\tvar (\n\t\t\t\tref = &schema.Table{\n\t\t\t\t\tName: \"t2\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t\t{Name: \"ref_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tfrom = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"t2_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tto = &schema.Table{\n\t\t\t\t\tName: \"t1\",\n\t\t\t\t\tSchema: &schema.Schema{\n\t\t\t\t\t\tName: \"public\",\n\t\t\t\t\t},\n\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t{Name: \"t2_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t)\n\t\t\tfrom.ForeignKeys = []*schema.ForeignKey{\n\t\t\t\t{Symbol: \"fk1\", Table: to, Columns: to.Columns, RefTable: ref, RefColumns: ref.Columns[1:]},\n\t\t\t\t{Symbol: \"1\", Table: from, Columns: from.Columns, RefTable: ref, RefColumns: ref.Columns[:1]},\n\t\t\t}\n\t\t\tto.ForeignKeys = []*schema.ForeignKey{\n\t\t\t\t{Symbol: \"fk1\", Table: to, Columns: to.Columns, RefTable: ref, RefColumns: ref.Columns[:1]},\n\t\t\t\t// The below \"constraint\" is identical to \"0\" above, therefore, the differ does not report a change.\n\t\t\t\t{Symbol: \"constraint\", Table: from, Columns: from.Columns, RefTable: ref, RefColumns: ref.Columns[:1]},\n\t\t\t}\n\t\t\treturn testcase{\n\t\t\t\tname: \"foreign-keys\",\n\t\t\t\tfrom: from,\n\t\t\t\tto:   to,\n\t\t\t\twantChanges: []schema.Change{\n\t\t\t\t\t&schema.ModifyForeignKey{\n\t\t\t\t\t\tFrom:   from.ForeignKeys[0],\n\t\t\t\t\t\tTo:     to.ForeignKeys[0],\n\t\t\t\t\t\tChange: schema.ChangeRefColumn,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t}(),\n\t}\n\tfor _, tt := range tests {\n\t\tdb, _, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\t\tdrv, err := Open(db)\n\t\trequire.NoError(t, err)\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tchanges, err := drv.TableDiff(tt.from, tt.to)\n\t\t\trequire.Equal(t, tt.wantErr, err != nil, err)\n\t\t\trequire.EqualValues(t, tt.wantChanges, changes)\n\t\t})\n\t}\n}\n\nfunc TestDiff_SchemaDiff(t *testing.T) {\n\tdb, _, err := sqlmock.New()\n\trequire.NoError(t, err)\n\tdrv, err := Open(db)\n\trequire.NoError(t, err)\n\tfrom := &schema.Schema{\n\t\tTables: []*schema.Table{\n\t\t\t{Name: \"users\"},\n\t\t\t{Name: \"pets\"},\n\t\t},\n\t}\n\tto := &schema.Schema{\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{Name: \"t2_id\", Type: &schema.ColumnType{Raw: \"int\", Type: &schema.IntegerType{T: \"int\"}}},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{Name: \"groups\"},\n\t\t},\n\t}\n\tfrom.Tables[0].Schema = from\n\tfrom.Tables[1].Schema = from\n\tchanges, err := drv.SchemaDiff(from, to)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, []schema.Change{\n\t\t&schema.ModifyTable{T: to.Tables[0], Changes: []schema.Change{&schema.AddColumn{C: to.Tables[0].Columns[0]}}},\n\t\t&schema.DropTable{T: from.Tables[1]},\n\t\t&schema.AddTable{T: to.Tables[1]},\n\t}, changes)\n}\n\nfunc TestDefaultDiff(t *testing.T) {\n\tchanges, err := DefaultDiff.SchemaDiff(\n\t\tschema.New(\"main\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"users\").AddColumns(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t),\n\t\tschema.New(\"main\"),\n\t)\n\trequire.NoError(t, err)\n\trequire.Len(t, changes, 1)\n\trequire.IsType(t, &schema.DropTable{}, changes[0])\n}\n"
  },
  {
    "path": "sql/sqlite/driver.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"hash/adler32\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n)\n\ntype (\n\t// Driver represents a SQLite driver for introspecting database schemas,\n\t// generating diff between schema elements and apply migrations changes.\n\tDriver struct {\n\t\t*conn\n\t\tschema.Differ\n\t\tschema.Inspector\n\t\tmigrate.PlanApplier\n\t}\n\n\t// database connection and its information.\n\tconn struct {\n\t\tschema.ExecQuerier\n\t\turl *sqlclient.URL\n\t}\n)\n\nvar _ interface {\n\tmigrate.StmtScanner\n\tschema.TypeParseFormatter\n} = (*Driver)(nil)\n\n// DriverName holds the name used for registration.\nconst DriverName = \"sqlite\"\n\nfunc init() {\n\tsqlclient.Register(\n\t\tDriverName,\n\t\tsqlclient.OpenerFunc(opener),\n\t\tsqlclient.RegisterDriverOpener(Open),\n\t\tsqlclient.RegisterTxOpener(OpenTx),\n\t\tsqlclient.RegisterCodec(codec, codec),\n\t\tsqlclient.RegisterFlavours(\"sqlite3\"),\n\t\tsqlclient.RegisterURLParser(urlparse{}),\n\t)\n\tsqlclient.Register(\n\t\t\"libsql\",\n\t\tsqlclient.DriverOpener(Open),\n\t\tsqlclient.RegisterTxOpener(OpenTx),\n\t\tsqlclient.RegisterCodec(codec, codec),\n\t\tsqlclient.RegisterFlavours(\"libsql+ws\", \"libsql+wss\", \"libsql+file\"),\n\t\tsqlclient.RegisterURLParser(sqlclient.URLParserFunc(func(u *url.URL) *sqlclient.URL {\n\t\t\tdsn := strings.TrimPrefix(u.String(), \"libsql+\")\n\t\t\tif strings.HasPrefix(dsn, \"file://\") {\n\t\t\t\tdsn = strings.Replace(dsn, \"file://\", \"file:\", 1)\n\t\t\t}\n\t\t\treturn &sqlclient.URL{URL: u, DSN: dsn, Schema: mainFile}\n\t\t})),\n\t)\n}\n\ntype urlparse struct{}\n\n// ParseURL implements the sqlclient.URLParser interface.\nfunc (urlparse) ParseURL(u *url.URL) *sqlclient.URL {\n\tuc := &sqlclient.URL{URL: u, DSN: strings.TrimPrefix(u.String(), u.Scheme+\"://\"), Schema: mainFile}\n\tif mode := u.Query().Get(\"mode\"); mode == \"memory\" {\n\t\t// The \"file:\" prefix is mandatory for memory modes.\n\t\tuc.DSN = \"file:\" + uc.DSN\n\t}\n\treturn uc\n}\n\nfunc opener(_ context.Context, u *url.URL) (*sqlclient.Client, error) {\n\tur := urlparse{}.ParseURL(u)\n\tdb, err := sql.Open(\"sqlite3\", ur.DSN)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdrv, err := Open(db)\n\tif err != nil {\n\t\tif cerr := db.Close(); cerr != nil {\n\t\t\terr = fmt.Errorf(\"%w: %v\", err, cerr)\n\t\t}\n\t\treturn nil, err\n\t}\n\tif drv, ok := drv.(*Driver); ok {\n\t\tdrv.url = ur\n\t}\n\treturn &sqlclient.Client{\n\t\tName:   DriverName,\n\t\tDB:     db,\n\t\tURL:    ur,\n\t\tDriver: drv,\n\t}, nil\n}\n\n// Open opens a new SQLite driver.\nfunc Open(db schema.ExecQuerier) (migrate.Driver, error) {\n\tc := &conn{ExecQuerier: db}\n\treturn &Driver{\n\t\tconn:        c,\n\t\tDiffer:      &sqlx.Diff{DiffDriver: &diff{}},\n\t\tInspector:   &inspect{c},\n\t\tPlanApplier: &planApply{c},\n\t}, nil\n}\n\n// Snapshot implements migrate.Snapshoter.\nfunc (d *Driver) Snapshot(ctx context.Context) (migrate.RestoreFunc, error) {\n\tr, err := d.InspectRealm(ctx, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !(r == nil || (len(r.Schemas) == 1 && r.Schemas[0].Name == mainFile && len(r.Schemas[0].Tables) == 0)) {\n\t\treturn nil, &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found table %q\", r.Schemas[0].Tables[0].Name)}\n\t}\n\treturn func(ctx context.Context) error {\n\t\tfor _, stmt := range []string{\n\t\t\t\"PRAGMA writable_schema = 1;\",\n\t\t\t\"DELETE FROM sqlite_master WHERE type IN ('table', 'view', 'index', 'trigger');\",\n\t\t\t\"PRAGMA writable_schema = 0;\",\n\t\t\t\"VACUUM;\",\n\t\t} {\n\t\t\tif _, err := d.ExecContext(ctx, stmt); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}, nil\n}\n\n// CheckClean implements migrate.CleanChecker.\nfunc (d *Driver) CheckClean(ctx context.Context, revT *migrate.TableIdent) error {\n\tr, err := d.InspectRealm(ctx, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tswitch n := len(r.Schemas); {\n\tcase n > 1:\n\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found multiple schemas: %d\", len(r.Schemas))}\n\tcase n == 1 && r.Schemas[0].Name != mainFile:\n\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found schema %q\", r.Schemas[0].Name)}\n\tcase n == 1 && len(r.Schemas[0].Tables) > 1:\n\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found multiple tables: %d\", len(r.Schemas[0].Tables))}\n\tcase n == 1 && len(r.Schemas[0].Tables) == 1 && (revT == nil || r.Schemas[0].Tables[0].Name != revT.Name):\n\t\treturn &migrate.NotCleanError{State: r, Reason: fmt.Sprintf(\"found table %q\", r.Schemas[0].Tables[0].Name)}\n\t}\n\treturn nil\n}\n\n// Lock implements the schema.Locker interface.\nfunc (d *Driver) Lock(_ context.Context, name string, timeout time.Duration) (schema.UnlockFunc, error) {\n\t// If the URL was set and the database is a file, use its name in the lock file.\n\tif d.url != nil && strings.HasPrefix(d.url.DSN, \"file:\") {\n\t\tp := filepath.Join(d.url.Host, d.url.Path)\n\t\tname = fmt.Sprintf(\"%s_%s\", name, fmt.Sprintf(\"%x\", adler32.Checksum([]byte(p))))\n\t}\n\tpath := filepath.Join(os.TempDir(), name+\".lock\")\n\tc, err := os.ReadFile(path)\n\tif errors.Is(err, os.ErrNotExist) {\n\t\treturn acquireLock(path, timeout)\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/sqlite: reading lock dir: %w\", err)\n\t}\n\texpires, err := strconv.ParseInt(string(c), 10, 64)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/sqlite: invalid lock file format: parsing expiration date: %w\", err)\n\t}\n\tif time.Unix(0, expires).After(time.Now()) {\n\t\t// Lock is still valid.\n\t\treturn nil, fmt.Errorf(\"sql/sqlite: lock on %q already taken\", name)\n\t}\n\treturn acquireLock(path, timeout)\n}\n\n// FormatType converts schema type to its column form in the database.\nfunc (*Driver) FormatType(t schema.Type) (string, error) {\n\treturn FormatType(t)\n}\n\n// ParseType returns the schema.Type value represented by the given string.\nfunc (*Driver) ParseType(s string) (schema.Type, error) {\n\treturn ParseType(s)\n}\n\n// StmtBuilder is a helper method used to build statements with SQLite formatting.\nfunc (*Driver) StmtBuilder(opts migrate.PlanOptions) *sqlx.Builder {\n\treturn &sqlx.Builder{\n\t\tQuoteOpening: '`',\n\t\tQuoteClosing: '`',\n\t\tSchema:       opts.SchemaQualifier,\n\t\tIndent:       opts.Indent,\n\t}\n}\n\n// ScanStmts implements migrate.StmtScanner.\nfunc (*Driver) ScanStmts(input string) ([]*migrate.Stmt, error) {\n\treturn (&migrate.Scanner{\n\t\tScannerOptions: migrate.ScannerOptions{\n\t\t\tMatchBegin: true,\n\t\t\t// The following are not support by SQLite.\n\t\t\tMatchBeginAtomic: false,\n\t\t\tMatchDollarQuote: false,\n\t\t},\n\t}).Scan(input)\n}\n\nfunc acquireLock(path string, timeout time.Duration) (schema.UnlockFunc, error) {\n\tlock, err := os.Create(path)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/sqlite: creating lockfile %q: %w\", path, err)\n\t}\n\tif _, err := lock.Write([]byte(strconv.FormatInt(time.Now().Add(timeout).UnixNano(), 10))); err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/sqlite: writing to lockfile %q: %w\", path, err)\n\t}\n\tdefer lock.Close()\n\treturn func() error { return os.Remove(path) }, nil\n}\n\ntype violation struct {\n\ttbl, ref   string\n\trow, index int\n}\n\n// OpenTx opens a transaction. If foreign keys are enabled, it disables them, checks for constraint violations,\n// opens the transaction and before committing ensures no new violations have been introduced by whatever Atlas was\n// doing.\nfunc OpenTx(ctx context.Context, db *sql.DB, opts *sql.TxOptions) (*sqlclient.Tx, error) {\n\tvar on sql.NullBool\n\tif err := db.QueryRowContext(ctx, \"PRAGMA foreign_keys\").Scan(&on); err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/sqlite: querying 'foreign_keys' pragma: %w\", err)\n\t}\n\t// Disable the foreign_keys pragma in case it is enabled, and\n\t// toggle it back after transaction is committed or rolled back.\n\tif on.Bool {\n\t\t_, err := db.ExecContext(ctx, \"PRAGMA foreign_keys = off\")\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sql/sqlite: set 'foreign_keys = off': %w\", err)\n\t\t}\n\t}\n\ttx, err := db.BeginTx(ctx, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcm, err := CommitFunc(ctx, db, tx, on.Bool)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &sqlclient.Tx{\n\t\tTx:         tx,\n\t\tCommitFn:   cm,\n\t\tRollbackFn: RollbackFunc(ctx, db, tx, on.Bool),\n\t}, nil\n}\n\n// Tx wraps schema.ExecQuerier with the transaction methods.\ntype Tx interface {\n\tschema.ExecQuerier\n\tCommit() error\n\tRollback() error\n}\n\n// CommitFunc takes a transaction and ensures to toggle foreign keys back on after tx.Commit is called.\nfunc CommitFunc(ctx context.Context, db schema.ExecQuerier, tx Tx, on bool) (func() error, error) {\n\tvar (\n\t\tbefore []violation\n\t\terr    error\n\t)\n\tif on {\n\t\tbefore, err = violations(ctx, tx)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn func() error {\n\t\tif on {\n\t\t\tafter, err := violations(ctx, tx)\n\t\t\tif err != nil {\n\t\t\t\tif err2 := tx.Rollback(); err2 != nil {\n\t\t\t\t\terr = fmt.Errorf(\"%v: %w\", err2, err)\n\t\t\t\t}\n\t\t\t\treturn enableFK(ctx, db, on, err)\n\t\t\t}\n\t\t\tif vs := violationsDiff(before, after); len(vs) > 0 {\n\t\t\t\terr := fmt.Errorf(\"sql/sqlite: foreign key mismatch: %+v\", vs)\n\t\t\t\tif err2 := tx.Rollback(); err2 != nil {\n\t\t\t\t\terr = fmt.Errorf(\"%v: %w\", err2, err)\n\t\t\t\t}\n\t\t\t\treturn enableFK(ctx, db, on, err)\n\t\t\t}\n\t\t}\n\t\treturn enableFK(ctx, db, on, tx.Commit())\n\t}, nil\n}\n\n// RollbackFunc takes a transaction and ensures to toggle foreign keys back on after tx.Rollback is called.\nfunc RollbackFunc(ctx context.Context, db schema.ExecQuerier, tx Tx, on bool) func() error {\n\treturn func() error {\n\t\treturn enableFK(ctx, db, on, tx.Rollback())\n\t}\n}\n\nfunc enableFK(ctx context.Context, db schema.ExecQuerier, do bool, err error) error {\n\tif do {\n\t\t// Re-enable foreign key checks if they were enabled before.\n\t\tif _, err2 := db.ExecContext(ctx, \"PRAGMA foreign_keys = on\"); err2 != nil {\n\t\t\terr2 = fmt.Errorf(\"sql/sqlite: set 'foreign_keys = on': %w\", err2)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"%v: %w\", err2, err)\n\t\t\t}\n\t\t\treturn err2\n\t\t}\n\t}\n\treturn err\n}\n\nfunc violations(ctx context.Context, conn schema.ExecQuerier) ([]violation, error) {\n\trows, err := conn.QueryContext(ctx, \"PRAGMA foreign_key_check\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/sqlite: querying 'foreign_key_check' pragma: %w\", err)\n\t}\n\tdefer rows.Close()\n\tvar vs []violation\n\tfor rows.Next() {\n\t\tvar v violation\n\t\tif err := rows.Scan(&v.tbl, &v.row, &v.ref, &v.index); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sql/sqlite: querying 'foreign_key_check' pragma: scanning rows: %w\", err)\n\t\t}\n\t\tvs = append(vs, v)\n\t}\n\tif err := rows.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"sql/sqlite: querying 'foreign_key_check' pragma: scanning rows: %w\", err)\n\t}\n\treturn vs, nil\n}\n\n// equalViolations compares the foreign key violations before starting a transaction with the ones afterwards.\n// It returns violations found in v2 that are not in v1.\nfunc violationsDiff(v1, v2 []violation) (vs []violation) {\n\tfor _, v := range v2 {\n\t\tif !contains(v1, v) {\n\t\t\tvs = append(vs, v)\n\t\t}\n\t}\n\treturn vs\n}\n\nfunc contains(hs []violation, n violation) bool {\n\tfor _, v := range hs {\n\t\tif v.row == n.row && v.ref == n.ref && v.index == n.index && v.tbl == n.tbl {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// SQLite standard data types as defined in its codebase and documentation.\n// https://www.sqlite.org/datatype3.html\n// https://github.com/sqlite/sqlite/blob/master/src/global.c\nconst (\n\tTypeInteger = \"integer\" // SQLITE_TYPE_INTEGER\n\tTypeReal    = \"real\"    // SQLITE_TYPE_REAL\n\tTypeText    = \"text\"    // SQLITE_TYPE_TEXT\n\tTypeBlob    = \"blob\"    // SQLITE_TYPE_BLOB\n)\n\n// SQLite generated columns types.\nconst (\n\tvirtual = \"VIRTUAL\"\n\tstored  = \"STORED\"\n)\n"
  },
  {
    "path": "sql/sqlite/driver_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage sqlite\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/specutil\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlspec\"\n)\n\n// InspectRealm returns schema descriptions of all resources in the given realm.\nfunc (i *inspect) InspectRealm(ctx context.Context, opts *schema.InspectRealmOption) (*schema.Realm, error) {\n\tschemas, err := i.databases(ctx, opts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(schemas) > 1 {\n\t\treturn nil, fmt.Errorf(\"sqlite: multiple database files are not supported by the driver. got: %d\", len(schemas))\n\t}\n\tif opts == nil {\n\t\topts = &schema.InspectRealmOption{}\n\t}\n\tvar (\n\t\tr    = schema.NewRealm(schemas...)\n\t\tmode = sqlx.ModeInspectRealm(opts)\n\t)\n\tif mode.Is(schema.InspectTables) {\n\t\tfor _, s := range schemas {\n\t\t\ttables, err := i.tables(ctx, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\ts.AddTables(tables...)\n\t\t\tfor _, t := range tables {\n\t\t\t\tif err := i.inspectTable(ctx, t); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tsqlx.LinkSchemaTables(r.Schemas)\n\t}\n\tif mode.Is(schema.InspectViews) {\n\t\tif err := i.inspectViews(ctx, r, nil); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif mode.Is(schema.InspectTriggers) {\n\t\tif err := i.inspectTriggers(ctx, r, nil); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn schema.ExcludeRealm(r, opts.Exclude)\n}\n\n// InspectSchema returns schema descriptions of the tables in the given schema.\n// If the schema name is empty, the \"main\" database is used.\nfunc (i *inspect) InspectSchema(ctx context.Context, name string, opts *schema.InspectOptions) (*schema.Schema, error) {\n\tif name == \"\" {\n\t\tname = mainFile\n\t}\n\tschemas, err := i.databases(ctx, &schema.InspectRealmOption{\n\t\tSchemas: []string{name},\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(schemas) == 0 {\n\t\treturn nil, &schema.NotExistError{\n\t\t\tErr: fmt.Errorf(\"sqlite: schema %q was not found\", name),\n\t\t}\n\t}\n\tif opts == nil {\n\t\topts = &schema.InspectOptions{}\n\t}\n\tvar (\n\t\tr    = schema.NewRealm(schemas...)\n\t\tmode = sqlx.ModeInspectSchema(opts)\n\t)\n\tif mode.Is(schema.InspectTables) {\n\t\ttables, err := i.tables(ctx, opts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tr.Schemas[0].AddTables(tables...)\n\t\tfor _, t := range tables {\n\t\t\tif err := i.inspectTable(ctx, t); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tsqlx.LinkSchemaTables(schemas)\n\t}\n\tif mode.Is(schema.InspectViews) {\n\t\tif err := i.inspectViews(ctx, r, opts); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif mode.Is(schema.InspectTriggers) {\n\t\tif err := i.inspectTriggers(ctx, r, nil); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn schema.ExcludeSchema(r.Schemas[0], opts.Exclude)\n}\n\nvar (\n\tspecOptions []schemahcl.Option\n\tscanFuncs   = &specutil.ScanFuncs{\n\t\tTable: convertTable,\n\t\tView:  convertView,\n\t}\n)\n\nfunc triggersSpec([]*schema.Trigger, *specutil.Doc) ([]*sqlspec.Trigger, error) {\n\treturn nil, nil // unimplemented.\n}\n\nfunc (*inspect) inspectViews(context.Context, *schema.Realm, *schema.InspectOptions) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*inspect) inspectTriggers(context.Context, *schema.Realm, *schema.InspectOptions) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) addView(*schema.AddView) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) dropView(*schema.DropView) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) modifyView(*schema.ModifyView) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) renameView(*schema.RenameView) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) addTrigger(*schema.AddTrigger) error {\n\treturn nil // unimplemented.\n}\n\nfunc (*state) dropTrigger(*schema.DropTrigger) error {\n\treturn nil // unimplemented.\n}\n\nfunc verifyChanges(context.Context, []schema.Change) error {\n\treturn nil // unimplemented.\n}\n\n// SupportChange reports if the change is supported by the differ.\nfunc (*diff) SupportChange(c schema.Change) bool {\n\tswitch c.(type) {\n\tcase *schema.RenameConstraint:\n\t\treturn false\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "sql/sqlite/driver_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"context\"\n\t\"database/sql/driver\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype mockDriver struct {\n\tdriver.Driver\n\topened []string\n}\n\nfunc (m *mockDriver) Open(name string) (driver.Conn, error) {\n\tdb, _, err := sqlmock.New()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tm.opened = append(m.opened, name)\n\treturn db.Driver().Open(name)\n}\n\nfunc TestDriver_LockAcquired(t *testing.T) {\n\tdrv := &Driver{conn: &conn{}}\n\n\t// Acquiring a lock does work.\n\tunlock, err := drv.Lock(context.Background(), \"lock\", time.Second)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, unlock)\n\n\t// Acquiring a lock on the same value will fail.\n\t_, err = drv.Lock(context.Background(), \"lock\", time.Second)\n\trequire.Error(t, err)\n\n\t// After unlock it will succeed again.\n\trequire.NoError(t, unlock())\n\t_, err = drv.Lock(context.Background(), \"lock\", time.Second)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, unlock)\n\n\t// Acquiring a lock on a value that has been expired works.\n\tdir, err := os.UserCacheDir()\n\trequire.NoError(t, err)\n\trequire.NoError(t, os.WriteFile(\n\t\tfilepath.Join(dir, \"lock.lock\"),\n\t\t[]byte(strconv.FormatInt(time.Now().Add(-time.Second).UnixNano(), 10)),\n\t\t0666,\n\t))\n\t_, err = drv.Lock(context.Background(), \"lock\", time.Second)\n\n\t// Acquiring a lock on another value works as well.\n\t_, err = drv.Lock(context.Background(), \"another\", time.Second)\n}\n\nfunc TestDriver_CheckClean(t *testing.T) {\n\tvar (\n\t\tr   = schema.NewRealm()\n\t\tdrv = &Driver{Inspector: &mockInspector{realm: r}}\n\t)\n\t// Empty realm.\n\terr := drv.CheckClean(context.Background(), nil)\n\trequire.NoError(t, err)\n\t// Empty schema.\n\tr.AddSchemas(schema.New(\"main\"))\n\terr = drv.CheckClean(context.Background(), nil)\n\trequire.NoError(t, err)\n\t// Schema with revisions table only.\n\tr.Schemas[0].AddTables(schema.NewTable(\"revisions\"))\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Name: \"revisions\"})\n\trequire.NoError(t, err)\n\t// Unknown table.\n\tr.Schemas[0].Tables[0].Name = \"unknown\"\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Name: \"revisions\"})\n\trequire.EqualError(t, err, `sql/migrate: connected database is not clean: found table \"unknown\"`)\n\t// Multiple tables.\n\tr.Schemas[0].Tables = []*schema.Table{schema.NewTable(\"a\"), schema.NewTable(\"revisions\")}\n\terr = drv.CheckClean(context.Background(), &migrate.TableIdent{Schema: \"test\", Name: \"revisions\"})\n\trequire.EqualError(t, err, `sql/migrate: connected database is not clean: found multiple tables: 2`)\n}\n\ntype mockInspector struct {\n\tschema.Inspector\n\trealm *schema.Realm\n}\n\nfunc (m *mockInspector) InspectRealm(context.Context, *schema.InspectRealmOption) (*schema.Realm, error) {\n\treturn m.realm, nil\n}\n"
  },
  {
    "path": "sql/sqlite/inspect.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// A diff provides an SQLite implementation for schema.Inspector.\ntype inspect struct{ *conn }\n\nvar _ schema.Inspector = (*inspect)(nil)\n\nfunc (i *inspect) inspectTable(ctx context.Context, t *schema.Table) error {\n\tif err := i.columns(ctx, t); err != nil {\n\t\treturn err\n\t}\n\tif err := i.indexes(ctx, t); err != nil {\n\t\treturn err\n\t}\n\tif err := i.fks(ctx, t); err != nil {\n\t\treturn err\n\t}\n\treturn fillChecks(t)\n}\n\n// columns queries and appends the columns of the given table.\nfunc (i *inspect) columns(ctx context.Context, t *schema.Table) error {\n\trows, err := i.QueryContext(ctx, fmt.Sprintf(columnsQuery, t.Name))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"sqlite: querying %q columns: %w\", t.Name, err)\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tif err := i.addColumn(t, rows); err != nil {\n\t\t\treturn fmt.Errorf(\"sqlite: %w\", err)\n\t\t}\n\t}\n\treturn autoinc(t)\n}\n\n// addColumn scans the current row and adds a new column from it to the table.\nfunc (i *inspect) addColumn(t *schema.Table, rows *sql.Rows) error {\n\tvar (\n\t\tnullable, primary   bool\n\t\thidden              sql.NullInt64\n\t\tname, typ, defaults sql.NullString\n\t\terr                 error\n\t)\n\tif err = rows.Scan(&name, &typ, &nullable, &defaults, &primary, &hidden); err != nil {\n\t\treturn err\n\t}\n\tc := &schema.Column{\n\t\tName: name.String,\n\t\tType: &schema.ColumnType{\n\t\t\tRaw:  typ.String,\n\t\t\tNull: nullable,\n\t\t},\n\t}\n\tc.Type.Type, err = ParseType(typ.String)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif defaults.Valid {\n\t\tc.Default = defaultExpr(defaults.String)\n\t}\n\t// The hidden flag is set to 2 for VIRTUAL columns, and to\n\t// 3 for STORED columns. See: sqlite/pragma.c#sqlite3Pragma.\n\tif hidden.Int64 >= 2 {\n\t\tif err := setGenExpr(t, c, hidden.Int64); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tt.Columns = append(t.Columns, c)\n\tif primary {\n\t\tif t.PrimaryKey == nil {\n\t\t\tt.SetPrimaryKey(&schema.Index{\n\t\t\t\tName:   \"PRIMARY\",\n\t\t\t\tUnique: true,\n\t\t\t\tTable:  t,\n\t\t\t})\n\t\t}\n\t\t// Columns are ordered by the `pk` field.\n\t\tt.PrimaryKey.Parts = append(t.PrimaryKey.Parts, &schema.IndexPart{\n\t\t\tC:     c,\n\t\t\tSeqNo: len(t.PrimaryKey.Parts) + 1,\n\t\t})\n\t}\n\treturn nil\n}\n\n// indexes queries and appends the indexes of the given table.\nfunc (i *inspect) indexes(ctx context.Context, t *schema.Table) error {\n\trows, err := i.QueryContext(ctx, fmt.Sprintf(indexesQuery, t.Name))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"sqlite: querying %q indexes: %w\", t.Name, err)\n\t}\n\tif err := i.addIndexes(t, rows); err != nil {\n\t\treturn fmt.Errorf(\"sqlite: scan %q indexes: %w\", t.Name, err)\n\t}\n\tfor _, idx := range t.Indexes {\n\t\tif err := i.indexInfo(ctx, t, idx); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// addIndexes scans the rows and adds the indexes to the table.\nfunc (i *inspect) addIndexes(t *schema.Table, rows *sql.Rows) error {\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tuniq, partial      bool\n\t\t\tname, origin, stmt sql.NullString\n\t\t)\n\t\tif err := rows.Scan(&name, &uniq, &origin, &partial, &stmt); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif origin.String == \"pk\" {\n\t\t\tcontinue\n\t\t}\n\t\tidx := &schema.Index{\n\t\t\tName:   name.String,\n\t\t\tUnique: uniq,\n\t\t\tTable:  t,\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&CreateStmt{S: stmt.String},\n\t\t\t\t&IndexOrigin{O: origin.String},\n\t\t\t},\n\t\t}\n\t\tif partial {\n\t\t\ti := strings.Index(stmt.String, \"WHERE\")\n\t\t\tif i == -1 {\n\t\t\t\treturn fmt.Errorf(\"missing partial WHERE clause in: %s\", stmt.String)\n\t\t\t}\n\t\t\tidx.Attrs = append(idx.Attrs, &IndexPredicate{\n\t\t\t\tP: strings.TrimSpace(stmt.String[i+5:]),\n\t\t\t})\n\t\t}\n\t\tt.Indexes = append(t.Indexes, idx)\n\t}\n\treturn nil\n}\n\nvar (\n\t// A regexp to extract index parts.\n\treIdxParts = regexp.MustCompile(\"(?i)ON\\\\s+[\\\"`]*(?:\\\\w+)[\\\"`]*\\\\s*\\\\((.+?)\\\\)(\\\\s*WHERE\\\\s+.+)?$\")\n\treIdxDesc  = regexp.MustCompile(\"(?i)\\\\s+DESC\\\\s*$\")\n)\n\nfunc (i *inspect) indexInfo(ctx context.Context, t *schema.Table, idx *schema.Index) error {\n\tvar (\n\t\thasExpr   bool\n\t\trows, err = i.QueryContext(ctx, fmt.Sprintf(indexColumnsQuery, idx.Name))\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"sqlite: querying %q indexes: %w\", t.Name, err)\n\t}\n\tdefer rows.Close()\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tdesc sql.NullBool\n\t\t\tname sql.NullString\n\t\t)\n\t\tif err := rows.Scan(&name, &desc); err != nil {\n\t\t\treturn fmt.Errorf(\"sqlite: scanning index names: %w\", err)\n\t\t}\n\t\tpart := &schema.IndexPart{\n\t\t\tSeqNo: len(idx.Parts) + 1,\n\t\t\tDesc:  desc.Bool,\n\t\t}\n\t\tswitch c, ok := t.Column(name.String); {\n\t\tcase ok:\n\t\t\tpart.C = c\n\t\t// NULL name indicates that the index-part is an expression and we\n\t\t// should extract it from the `CREATE INDEX` statement (not supported atm).\n\t\tcase !sqlx.ValidString(name):\n\t\t\thasExpr = true\n\t\t\tpart.X = &schema.RawExpr{X: \"<unsupported>\"}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"sqlite: column %q was not found for index %q\", name.String, idx.Name)\n\t\t}\n\t\tidx.Parts = append(idx.Parts, part)\n\t}\n\tif !hasExpr {\n\t\treturn nil\n\t}\n\tvar c CreateStmt\n\tif !sqlx.Has(idx.Attrs, &c) || !reIdxParts.MatchString(c.S) {\n\t\treturn nil\n\t}\n\tx := reIdxParts.FindStringSubmatch(c.S)[1]\n\tfor _, p := range idx.Parts {\n\t\tj := sqlx.ExprLastIndex(x)\n\t\t// Unable to parse index parts correctly.\n\t\tif j == -1 {\n\t\t\treturn nil\n\t\t}\n\t\tif p.X != nil {\n\t\t\t// Remove any extra spaces and the \"DESC\" clause\n\t\t\t// in case the key-part is descending.\n\t\t\tkx := strings.TrimSpace(x[:j+1])\n\t\t\tif p.Desc {\n\t\t\t\tkx = reIdxDesc.ReplaceAllString(kx, \"\")\n\t\t\t}\n\t\t\tp.X.(*schema.RawExpr).X = kx\n\t\t}\n\t\tx = strings.TrimLeft(x[j+1:], \", \")\n\t}\n\treturn nil\n}\n\n// fks queries and appends the foreign-keys of the given table.\nfunc (i *inspect) fks(ctx context.Context, t *schema.Table) error {\n\trows, err := i.QueryContext(ctx, fmt.Sprintf(fksQuery, t.Name))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"sqlite: querying %q foreign-keys: %w\", t.Name, err)\n\t}\n\tif err := i.addFKs(t, rows); err != nil {\n\t\treturn fmt.Errorf(\"sqlite: scan %q foreign-keys: %w\", t.Name, err)\n\t}\n\treturn fillConstName(t)\n}\n\nfunc (i *inspect) addFKs(t *schema.Table, rows *sql.Rows) error {\n\tids := make(map[int]*schema.ForeignKey)\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tid                                                  int\n\t\t\tcolumn, refColumn, refTable, updateRule, deleteRule string\n\t\t)\n\t\tif err := rows.Scan(&id, &column, &refColumn, &refTable, &updateRule, &deleteRule); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfk, ok := ids[id]\n\t\tif !ok {\n\t\t\tfk = &schema.ForeignKey{\n\t\t\t\tSymbol:   strconv.Itoa(id),\n\t\t\t\tTable:    t,\n\t\t\t\tRefTable: t,\n\t\t\t\tOnDelete: schema.ReferenceOption(deleteRule),\n\t\t\t\tOnUpdate: schema.ReferenceOption(updateRule),\n\t\t\t}\n\t\t\tif refTable != t.Name {\n\t\t\t\tfk.RefTable = &schema.Table{Name: refTable, Schema: &schema.Schema{Name: t.Schema.Name}}\n\t\t\t}\n\t\t\tids[id] = fk\n\t\t\tt.ForeignKeys = append(t.ForeignKeys, fk)\n\t\t}\n\t\tc, ok := t.Column(column)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"column %q was not found for fk %q\", column, fk.Symbol)\n\t\t}\n\t\t// Rows are ordered by SEQ that specifies the\n\t\t// position of the column in the FK definition.\n\t\tif _, ok := fk.Column(c.Name); !ok {\n\t\t\tfk.Columns = append(fk.Columns, c)\n\t\t\tc.ForeignKeys = append(c.ForeignKeys, fk)\n\t\t}\n\n\t\t// Stub referenced columns or link if it is a self-reference.\n\t\tvar rc *schema.Column\n\t\tif fk.Table != fk.RefTable {\n\t\t\trc = &schema.Column{Name: refColumn}\n\t\t} else if c, ok := t.Column(refColumn); ok {\n\t\t\trc = c\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"referenced column %q was not found for fk %q\", refColumn, fk.Symbol)\n\t\t}\n\t\tif _, ok := fk.RefColumn(rc.Name); !ok {\n\t\t\tfk.RefColumns = append(fk.RefColumns, rc)\n\t\t}\n\t}\n\treturn nil\n}\n\n// tableNames returns a list of all tables exist in the schema.\nfunc (i *inspect) tables(ctx context.Context, opts *schema.InspectOptions) ([]*schema.Table, error) {\n\tvar (\n\t\targs  []any\n\t\tquery = tablesQuery\n\t)\n\tif opts != nil && len(opts.Tables) > 0 {\n\t\tquery += \" AND sqlite_master.name IN (\" + strings.Repeat(\"?, \", len(opts.Tables)-1) + \"?)\"\n\t\tfor _, s := range opts.Tables {\n\t\t\targs = append(args, s)\n\t\t}\n\t}\n\trows, err := i.QueryContext(ctx, query, args...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sqlite: querying schema tables: %w\", err)\n\t}\n\tdefer rows.Close()\n\tvar tables []*schema.Table\n\tfor rows.Next() {\n\t\tvar (\n\t\t\tname, stmt string\n\t\t\twr, strict sql.NullBool\n\t\t)\n\t\tif err := rows.Scan(&name, &stmt, &wr, &strict); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sqlite: scanning table: %w\", err)\n\t\t}\n\t\tstmt = strings.TrimSpace(stmt)\n\t\tt := &schema.Table{\n\t\t\tName: name,\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&CreateStmt{S: strings.TrimSpace(stmt)},\n\t\t\t},\n\t\t}\n\t\tif wr.Bool {\n\t\t\tt.Attrs = append(t.Attrs, &WithoutRowID{})\n\t\t}\n\t\tif strict.Bool {\n\t\t\tt.Attrs = append(t.Attrs, &Strict{})\n\t\t}\n\t\ttables = append(tables, t)\n\t}\n\treturn tables, nil\n}\n\n// schemas returns the list of the schemas in the database.\nfunc (i *inspect) databases(ctx context.Context, opts *schema.InspectRealmOption) ([]*schema.Schema, error) {\n\tvar (\n\t\targs  []any\n\t\tquery = databasesQuery\n\t)\n\tif opts != nil && len(opts.Schemas) > 0 {\n\t\tquery = fmt.Sprintf(databasesQueryArgs, strings.Repeat(\"?, \", len(opts.Schemas)-1)+\"?\")\n\t\tfor _, s := range opts.Schemas {\n\t\t\targs = append(args, s)\n\t\t}\n\t}\n\trows, err := i.QueryContext(ctx, query, args...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"sqlite: querying schemas: %w\", err)\n\t}\n\tdefer rows.Close()\n\tvar schemas []*schema.Schema\n\tfor rows.Next() {\n\t\tvar name, file sql.NullString\n\t\tif err := rows.Scan(&name, &file); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// File is missing if the database is not\n\t\t// associated with a file (:memory: mode).\n\t\tif file.String == \"\" {\n\t\t\tfile.String = \":memory:\"\n\t\t}\n\t\tschemas = append(schemas, &schema.Schema{\n\t\t\tName:  name.String,\n\t\t\tAttrs: []schema.Attr{&File{Name: file.String}},\n\t\t})\n\t}\n\treturn schemas, nil\n}\n\ntype (\n\t// File describes a database file.\n\tFile struct {\n\t\tschema.Attr\n\t\tName string\n\t}\n\n\t// CreateStmt describes the SQL statement used to create a resource.\n\tCreateStmt struct {\n\t\tschema.Attr\n\t\tS string\n\t}\n\n\t// AutoIncrement describes the `AUTOINCREMENT` configuration.\n\t// https://www.sqlite.org/autoinc.html\n\tAutoIncrement struct {\n\t\tschema.Attr\n\t\t// Seq represents the value in sqlite_sequence table.\n\t\t// i.e. https://www.sqlite.org/fileformat2.html#seqtab.\n\t\t//\n\t\t// Setting this value manually to > 0 indicates that\n\t\t// a custom value is necessary and should be handled\n\t\t// on migrate.\n\t\tSeq int64\n\t}\n\n\t// WithoutRowID describes the `WITHOUT ROWID` configuration.\n\t// See: https://sqlite.org/withoutrowid.html\n\tWithoutRowID struct {\n\t\tschema.Attr\n\t}\n\n\t// Strict describes the `STRICT` configuration.\n\t// See: https://sqlite.org/stricttables.html\n\tStrict struct {\n\t\tschema.Attr\n\t}\n\n\t// IndexPredicate describes a partial index predicate.\n\t// See: https://www.sqlite.org/partialindex.html\n\tIndexPredicate struct {\n\t\tschema.Attr\n\t\tP string\n\t}\n\n\t// IndexOrigin describes how the index was created.\n\t// See: https://www.sqlite.org/pragma.html#pragma_index_list\n\tIndexOrigin struct {\n\t\tschema.Attr\n\t\tO string\n\t}\n\n\t// A UUIDType defines a UUID type.\n\t//\n\t// Deprecated: Use schema.UUIDType instead.\n\tUUIDType = schema.UUIDType\n\n\t// UserDefinedType defines a user-defined type attribute.\n\tUserDefinedType struct {\n\t\tschema.Type\n\t\tT string\n\t}\n)\n\nfunc columnParts(t string) []string {\n\tt = strings.TrimSpace(strings.ToLower(t))\n\tparts := strings.FieldsFunc(t, func(r rune) bool {\n\t\treturn r == '(' || r == ')' || r == ' ' || r == ','\n\t})\n\tfor k := 0; k < 2; k++ {\n\t\t// Join the type back if it was separated with space (e.g. 'varying character').\n\t\tif len(parts) > 1 && !sqlx.IsUint(parts[0]) && !sqlx.IsUint(parts[1]) {\n\t\t\tparts[1] = parts[0] + \" \" + parts[1]\n\t\t\tparts = parts[1:]\n\t\t}\n\t}\n\treturn parts\n}\n\nfunc defaultExpr(x string) schema.Expr {\n\tswitch {\n\t// Literals definition.\n\t// https://www.sqlite.org/syntax/literal-value.html\n\tcase sqlx.IsLiteralBool(x), sqlx.IsLiteralNumber(x), sqlx.IsQuoted(x, '\"', '\\''), isBlob(x):\n\t\treturn &schema.Literal{V: x}\n\tdefault:\n\t\t// We wrap the CURRENT_TIMESTAMP literals in raw-expressions\n\t\t// as they are not parsable in most decoders.\n\t\treturn &schema.RawExpr{X: x}\n\t}\n}\n\n// blob literals are hex strings preceded by 'x' (or 'X).\nfunc isBlob(s string) bool {\n\tif (strings.HasPrefix(s, \"x'\") || strings.HasPrefix(s, \"X'\")) && strings.HasSuffix(s, \"'\") {\n\t\t_, err := strconv.ParseUint(s[2:len(s)-1], 16, 64)\n\t\treturn err == nil\n\t}\n\treturn false\n}\n\nvar reAutoinc = regexp.MustCompile(\"(?i)(?:[(,]\\\\s*)[\\\"`]?(\\\\w+)[\\\"`]?\\\\s+INTEGER\\\\s+[^,]*PRIMARY\\\\s+KEY\\\\s+[^,]*AUTOINCREMENT\")\n\n// autoinc checks if the table contains a \"PRIMARY KEY AUTOINCREMENT\" on its\n// CREATE statement, according to https://www.sqlite.org/syntax/column-constraint.html.\n// This is a workaround until we will embed a proper SQLite parser in atlas.\nfunc autoinc(t *schema.Table) error {\n\tvar c CreateStmt\n\tif !sqlx.Has(t.Attrs, &c) {\n\t\treturn fmt.Errorf(\"missing CREATE statement for table: %q\", t.Name)\n\t}\n\tif t.PrimaryKey == nil || len(t.PrimaryKey.Parts) != 1 || t.PrimaryKey.Parts[0].C == nil {\n\t\treturn nil\n\t}\n\tmatches := reAutoinc.FindStringSubmatch(c.S)\n\tif len(matches) != 2 {\n\t\treturn nil\n\t}\n\tpkc, ok := t.Column(matches[1])\n\tif !ok {\n\t\treturn fmt.Errorf(\"sqlite: column %q was not found for AUTOINCREMENT\", matches[1])\n\t}\n\tif t.PrimaryKey == nil || len(t.PrimaryKey.Parts) != 1 || t.PrimaryKey.Parts[0].C != pkc {\n\t\treturn fmt.Errorf(\"sqlite: unexpected primary key: %v\", t.PrimaryKey)\n\t}\n\tinc := &AutoIncrement{}\n\t// Annotate table elements with \"AUTOINCREMENT\".\n\tt.PrimaryKey.Attrs = append(t.PrimaryKey.Attrs, inc)\n\tpkc.Attrs = append(pkc.Attrs, inc)\n\treturn nil\n}\n\n// setGenExpr extracts the generated expression from the CREATE statement\n// and appends it to the column.\nfunc setGenExpr(t *schema.Table, c *schema.Column, f int64) error {\n\tvar s CreateStmt\n\tif !sqlx.Has(t.Attrs, &s) {\n\t\treturn fmt.Errorf(\"missing CREATE statement for table: %q\", t.Name)\n\t}\n\tre, err := regexp.Compile(fmt.Sprintf(\"(?:[(,]\\\\s*)[\\\"`]*(%s)[\\\"`]*[^,]*(?i:GENERATED\\\\s+ALWAYS)*\\\\s*(?i:AS){1}\\\\s*\\\\(\", c.Name))\n\tif err != nil {\n\t\treturn err\n\t}\n\tidx := re.FindAllStringIndex(s.S, 1)\n\tif len(idx) != 1 || len(idx[0]) != 2 {\n\t\treturn fmt.Errorf(\"sqlite: generation expression for column %q was not found in create statement\", c.Name)\n\t}\n\texpr := scanExpr(s.S[idx[0][1]-1:])\n\tif expr == \"\" {\n\t\treturn fmt.Errorf(\"sqlite: unexpected empty generation expression for column %q\", c.Name)\n\t}\n\ttyp := virtual\n\tif f == 3 {\n\t\ttyp = stored\n\t}\n\tc.SetGeneratedExpr(&schema.GeneratedExpr{Expr: expr, Type: typ})\n\treturn nil\n}\n\n// The following regexes extract named FKs and CHECK constraints defined in table-constraints or inlined\n// as column-constraints. Note, we assume the SQL statements are valid as they are returned by SQLite.\nvar (\n\treFKC   = regexp.MustCompile(\"(?i)(?:[(,]\\\\s*)[\\\"`]*(\\\\w+)[\\\"`]*[^,]*\\\\s+CONSTRAINT\\\\s+[\\\"`]*(\\\\w+)[\\\"`]*\\\\s+REFERENCES\\\\s+[\\\"`]*(\\\\w+)[\\\"`]*\\\\s*\\\\(([,\\\"` \\\\w]+)\\\\)\")\n\treFKT   = regexp.MustCompile(\"(?i)CONSTRAINT\\\\s+[\\\"`]*(\\\\w+)[\\\"`]*\\\\s+FOREIGN\\\\s+KEY\\\\s*\\\\(([,\\\"` \\\\w]+)\\\\)\\\\s+REFERENCES\\\\s+[\\\"`]*(\\\\w+)[\\\"`]*\\\\s*\\\\(([,\\\"` \\\\w]+)\\\\)\")\n\treCheck = regexp.MustCompile(\"(?i)(?:CONSTRAINT\\\\s+[\\\"`]?(\\\\w+)[\\\"`]?\\\\s+)?CHECK\\\\s*\\\\(\")\n)\n\n// fillConstName fills foreign-key constrain names from CREATE TABLE statement.\nfunc fillConstName(t *schema.Table) error {\n\tvar c CreateStmt\n\tif !sqlx.Has(t.Attrs, &c) {\n\t\treturn fmt.Errorf(\"missing CREATE statement for table: %q\", t.Name)\n\t}\n\t// Loop over table constraints.\n\tfor _, m := range reFKT.FindAllStringSubmatch(c.S, -1) {\n\t\tif len(m) != 5 {\n\t\t\treturn fmt.Errorf(\"unexpected number of matches for a table constraint: %q\", m)\n\t\t}\n\t\t// Pattern matches \"constraint_name\", \"columns\", \"ref_table\" and \"ref_columns\".\n\t\tfor _, fk := range t.ForeignKeys {\n\t\t\t// Found a foreign-key match for the constraint.\n\t\t\tif matchFK(fk, columns(m[2]), m[3], columns(m[4])) {\n\t\t\t\tfk.Symbol = m[1]\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\t// Loop over inlined column constraints.\n\tfor _, m := range reFKC.FindAllStringSubmatch(c.S, -1) {\n\t\tif len(m) != 5 {\n\t\t\treturn fmt.Errorf(\"unexpected number of matches for a column constraint: %q\", m)\n\t\t}\n\t\t// Pattern matches \"column\", \"constraint_name\", \"ref_table\" and \"ref_columns\".\n\t\tfor _, fk := range t.ForeignKeys {\n\t\t\t// Found a foreign-key match for the constraint.\n\t\t\tif matchFK(fk, columns(m[1]), m[3], columns(m[4])) {\n\t\t\t\tfk.Symbol = m[2]\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// columns from the matched regex above.\nfunc columns(s string) []string {\n\tnames := strings.Split(s, \",\")\n\tfor i := range names {\n\t\tnames[i] = strings.Trim(strings.TrimSpace(names[i]), \"`\\\"\")\n\t}\n\treturn names\n}\n\n// matchFK reports if the foreign-key matches the given attributes.\nfunc matchFK(fk *schema.ForeignKey, columns []string, refTable string, refColumns []string) bool {\n\tif len(fk.Columns) != len(columns) || fk.RefTable.Name != refTable || len(fk.RefColumns) != len(refColumns) {\n\t\treturn false\n\t}\n\tfor i := range columns {\n\t\tif fk.Columns[i].Name != columns[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\tfor i := range refColumns {\n\t\tif fk.RefColumns[i].Name != refColumns[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// fillChecks extracts the CHECK constrains from the CREATE TABLE statement,\n// and appends them to the table attributes.\nfunc fillChecks(t *schema.Table) error {\n\tvar c CreateStmt\n\tif !sqlx.Has(t.Attrs, &c) {\n\t\treturn fmt.Errorf(\"missing CREATE statement for table: %q\", t.Name)\n\t}\n\tfor i := 0; i < len(c.S); {\n\t\tidx := reCheck.FindStringSubmatchIndex(c.S[i:])\n\t\t// No more matches.\n\t\tif len(idx) != 4 {\n\t\t\tbreak\n\t\t}\n\t\tcheck := &schema.Check{Expr: scanExpr(c.S[idx[1]-1:])}\n\t\t// Matching group for constraint name.\n\t\tif idx[2] != -1 && idx[3] != -1 {\n\t\t\tcheck.Name = c.S[idx[2]:idx[3]]\n\t\t}\n\t\tt.Attrs = append(t.Attrs, check)\n\t\tc.S = c.S[idx[1]+len(check.Expr)-1:]\n\t}\n\treturn nil\n}\n\n// scanExpr scans the expression string (wrapped with parens)\n// until its end in the given string. e.g. \"(a+1), c int ...\".\nfunc scanExpr(expr string) string {\n\tvar r, l int\n\tfor i := 0; i < len(expr); i++ {\n\t\tswitch expr[i] {\n\t\tcase '(':\n\t\t\tr++\n\t\tcase ')':\n\t\t\tl++\n\t\tcase '\\'', '\"':\n\t\t\t// Skip unescaped strings.\n\t\t\tif j := strings.IndexByte(expr[i+1:], expr[i]); j != -1 {\n\t\t\t\ti += j + 1\n\t\t\t}\n\t\t}\n\t\t// Balanced parens.\n\t\tif r == l {\n\t\t\treturn expr[:i+1]\n\t\t}\n\t}\n\treturn \"\"\n}\n\nconst (\n\t// Name of main database file.\n\tmainFile = \"main\"\n\t// Query to list attached database files.\n\tdatabasesQuery     = \"SELECT `name`, `file` FROM pragma_database_list() WHERE `name` <> 'temp'\"\n\tdatabasesQueryArgs = \"SELECT `name`, `file` FROM pragma_database_list() WHERE `name` IN (%s)\"\n\t// Query to list database tables.\n\ttablesQuery = `\nSELECT\n\tsqlite_master.name, sqlite_master.sql, wr, strict\nFROM\n\tsqlite_master\n\tJOIN pragma_table_list(sqlite_master.name)\nWHERE\n\tsqlite_master.type = 'table'\n\tAND sqlite_master.name NOT LIKE 'sqlite_%'\n\tAND sqlite_master.name NOT LIKE 'libsql_%'\n`\n\t// Query to list table information.\n\tcolumnsQuery = \"SELECT `name`, `type`, (not `notnull`) AS `nullable`, `dflt_value`, (`pk` <> 0) AS `pk`, `hidden` FROM pragma_table_xinfo('%s') ORDER BY `cid`\"\n\t// Query to list table indexes.\n\tindexesQuery = \"SELECT `il`.`name`, `il`.`unique`, `il`.`origin`, `il`.`partial`, `m`.`sql` FROM pragma_index_list('%s') AS il JOIN sqlite_master AS m ON il.name = m.name\"\n\t// Query to list index columns.\n\tindexColumnsQuery = \"SELECT name, desc FROM pragma_index_xinfo('%s') WHERE key = 1 ORDER BY seqno\"\n\t// Query to list table foreign-keys.\n\tfksQuery = \"SELECT `id`, `from`, `to`, `table`, `on_update`, `on_delete` FROM pragma_foreign_key_list('%s') ORDER BY id, seq\"\n)\n"
  },
  {
    "path": "sql/sqlite/inspect_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/internal/sqltest\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDriver_InspectTable(t *testing.T) {\n\ttests := []struct {\n\t\tname   string\n\t\tbefore func(mock)\n\t\texpect func(*require.Assertions, *schema.Table, error)\n\t}{\n\t\t{\n\t\t\tname: \"table columns\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"users\", true, \"CREATE TABLE users(id INTEGER PRIMARY KEY AUTOINCREMENT, w INT GENERATED ALWAYS AS (a*10), x TEXT AS (typeof(c)) STORED, y TEXT AS (substr(b,a,a+2)))\")\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(columnsQuery, \"users\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n name |   type       | nullable | dflt_value  | primary  | hidden\n------+--------------+----------+ ------------+----------+----------\n id   | integer       |  0      |     0x1     |  1       |  0\n c1   | int           |  1      |     a       |  0       |  0\n c2   | integer       |  0      |     97      |  0       |  0\n c3   | varchar(100)  |  1      |    'A'      |  0       |  0\n c4   | boolean       |  0      |             |  0       |  0\n c5   | json          |  0      |             |  0       |  0\n c6   | datetime      |  0      |             |  0       |  0\n c7   | blob          |  0      |    x'a'     |  0       |  0\n c8   | text          |  0      |             |  0       |  0\n c9   | numeric(10,2) |  0      |             |  0       |  0\n c10  | real          |  0      |             |  0       |  0\n c11  |               |  0      |             |  0       |  0\n w    | int           |  0      |             |  0       |  2\n x    | text          |  0      |             |  0       |  3\n y    | text          |  0      |             |  0       |  2\n j    | jsonb         |  0      |             |  0       |  0\n`))\n\t\t\t\tm.noIndexes(\"users\")\n\t\t\t\tm.noFKs(\"users\")\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\tcolumns := []*schema.Column{\n\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Raw: \"integer\"}, Attrs: []schema.Attr{&AutoIncrement{}}, Default: &schema.Literal{V: \"0x1\"}},\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Null: true, Type: &schema.IntegerType{T: \"int\"}, Raw: \"int\"}, Default: &schema.RawExpr{X: \"a\"}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Raw: \"integer\"}, Default: &schema.Literal{V: \"97\"}},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Null: true, Type: &schema.StringType{T: \"varchar\", Size: 100}, Raw: \"varchar(100)\"}, Default: &schema.Literal{V: \"'A'\"}},\n\t\t\t\t\t{Name: \"c4\", Type: &schema.ColumnType{Type: &schema.BoolType{T: \"boolean\"}, Raw: \"boolean\"}},\n\t\t\t\t\t{Name: \"c5\", Type: &schema.ColumnType{Type: &schema.JSONType{T: \"json\"}, Raw: \"json\"}},\n\t\t\t\t\t{Name: \"c6\", Type: &schema.ColumnType{Type: &schema.TimeType{T: \"datetime\"}, Raw: \"datetime\"}},\n\t\t\t\t\t{Name: \"c7\", Type: &schema.ColumnType{Type: &schema.BinaryType{T: \"blob\"}, Raw: \"blob\"}, Default: &schema.Literal{V: \"x'a'\"}},\n\t\t\t\t\t{Name: \"c8\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Raw: \"text\"}},\n\t\t\t\t\t{Name: \"c9\", Type: &schema.ColumnType{Type: &schema.DecimalType{T: \"numeric\", Precision: 10, Scale: 2}, Raw: \"numeric(10,2)\"}},\n\t\t\t\t\t{Name: \"c10\", Type: &schema.ColumnType{Type: &schema.FloatType{T: \"real\"}, Raw: \"real\"}},\n\t\t\t\t\t{Name: \"c11\", Type: &schema.ColumnType{Type: &schema.BinaryType{T: \"blob\"}, Raw: \"\"}},\n\t\t\t\t\t{Name: \"w\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}, Raw: \"int\"}, Attrs: []schema.Attr{&schema.GeneratedExpr{Type: \"VIRTUAL\", Expr: \"(a*10)\"}}},\n\t\t\t\t\t{Name: \"x\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Raw: \"text\"}, Attrs: []schema.Attr{&schema.GeneratedExpr{Type: \"STORED\", Expr: \"(typeof(c))\"}}},\n\t\t\t\t\t{Name: \"y\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Raw: \"text\"}, Attrs: []schema.Attr{&schema.GeneratedExpr{Type: \"VIRTUAL\", Expr: \"(substr(b,a,a+2))\"}}},\n\t\t\t\t\t{Name: \"j\", Type: &schema.ColumnType{Type: &schema.JSONType{T: \"jsonb\"}, Raw: \"jsonb\"}},\n\t\t\t\t}\n\t\t\t\trequire.Equal(t.Columns, columns)\n\t\t\t\trequire.EqualValues(&schema.Index{\n\t\t\t\t\tName:   \"PRIMARY\",\n\t\t\t\t\tUnique: true,\n\t\t\t\t\tTable:  t,\n\t\t\t\t\tParts:  []*schema.IndexPart{{SeqNo: 1, C: columns[0]}},\n\t\t\t\t\tAttrs:  []schema.Attr{&AutoIncrement{}},\n\t\t\t\t}, t.PrimaryKey)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"table indexes\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"users\", true, \"CREATE TABLE users(id INTEGER PRIMARY KEY)\")\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(columnsQuery, \"users\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n name |   type       | nullable | dflt_value  | primary  | hidden\n------+--------------+----------+ ------------+----------+----------\n c1   | int           |  1      |             |  0       |  0\n c2   | integer       |  0      |             |  0       |  0\n c3   | json          |  0      |             |  0       |  0\n`))\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexesQuery, \"users\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n name  |   unique     | origin | partial  |                      sql \n-------+--------------+--------+----------+-------------------------------------------------------\n c1u   |  1           |  c     |  0       | CREATE UNIQUE INDEX c1u on users(c1, c2)\n c1_c2 |  0           |  c     |  1       | CREATE INDEX c1_c2 on users(c1, c2*2) WHERE c1 <> NULL\n c1_x  |  0           |  c     |  0       | CREATE INDEX c1_x ON users (f(c1))\n c3_x  |  0           |  c     |  0       | CREATE INDEX c3_x ON users (json_extract(c3, '$.x') desc, json_extract(c3, '$.y') desc)\n`))\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexColumnsQuery, \"c1u\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n name  |   desc |\n-------+--------+\n c1   |  1      |\n c2   |  0      |\n`))\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexColumnsQuery, \"c1_c2\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n name  |   desc |     \n-------+--------+     \n c1    |  0     |     \n nil   |  0     |     \n`))\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexColumnsQuery, \"c1_x\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n name  |   desc |\n-------+--------+\n nil   |  0     |\n`))\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexColumnsQuery, \"c3_x\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n name  |   desc |\n-------+--------+\n nil   |  1     |\n nil   |  1     |\n`))\n\t\t\t\tm.noFKs(\"users\")\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\tcolumns := []*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Null: true, Type: &schema.IntegerType{T: \"int\"}, Raw: \"int\"}},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Raw: \"integer\"}},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Type: &schema.JSONType{T: \"json\"}, Raw: \"json\"}},\n\t\t\t\t}\n\t\t\t\tindexes := []*schema.Index{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:   \"c1u\",\n\t\t\t\t\t\tUnique: true,\n\t\t\t\t\t\tTable:  t,\n\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t{SeqNo: 1, C: columns[0], Desc: true},\n\t\t\t\t\t\t\t{SeqNo: 2, C: columns[1]},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&CreateStmt{S: \"CREATE UNIQUE INDEX c1u on users(c1, c2)\"},\n\t\t\t\t\t\t\t&IndexOrigin{O: \"c\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"c1_c2\",\n\t\t\t\t\t\tTable: t,\n\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t{SeqNo: 1, C: columns[0]},\n\t\t\t\t\t\t\t{SeqNo: 2, X: &schema.RawExpr{X: \"c2*2\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&CreateStmt{S: \"CREATE INDEX c1_c2 on users(c1, c2*2) WHERE c1 <> NULL\"},\n\t\t\t\t\t\t\t&IndexOrigin{O: \"c\"},\n\t\t\t\t\t\t\t&IndexPredicate{P: \"c1 <> NULL\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"c1_x\",\n\t\t\t\t\t\tTable: t,\n\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t{SeqNo: 1, X: &schema.RawExpr{X: \"f(c1)\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&CreateStmt{S: \"CREATE INDEX c1_x ON users (f(c1))\"},\n\t\t\t\t\t\t\t&IndexOrigin{O: \"c\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"c3_x\",\n\t\t\t\t\t\tTable: t,\n\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t{SeqNo: 1, X: &schema.RawExpr{X: \"json_extract(c3, '$.x')\"}, Desc: true},\n\t\t\t\t\t\t\t{SeqNo: 2, X: &schema.RawExpr{X: \"json_extract(c3, '$.y')\"}, Desc: true},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&CreateStmt{S: \"CREATE INDEX c3_x ON users (json_extract(c3, '$.x') desc, json_extract(c3, '$.y') desc)\"},\n\t\t\t\t\t\t\t&IndexOrigin{O: \"c\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\trequire.Equal(t.Columns, columns)\n\t\t\t\trequire.Equal(t.Indexes, indexes)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"table constraints\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.tableExists(\"users\", true, `\nCREATE TABLE users(\n\tid INTEGER PRIMARY KEY,\n\tc1 int CHECK (c1 > 10),\n\tc2 integer NOT NULL CONSTRAINT c2_fk REFERENCES users (c1) ON DELETE SET NULL constraint \"ck1\" CHECK ((c1 + c2) % 2 = 0),\n\tc3 integer NOT NULL REFERENCES users (c1) ON DELETE SET NULL,\n\tCONSTRAINT \"c1_c2_fk\" FOREIGN KEY (c1, c2) REFERENCES t2 (id, c1),\n\tCONSTRAINT \"id_nonzero\" CHECK (id <> 0)\n)\n`)\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(columnsQuery, \"users\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n name |   type       | nullable | dflt_value  | primary  | hidden\n------+--------------+----------+ ------------+----------+----------\n c1   | int           |  1      |             |  0       |  0\n c2   | integer       |  0      |             |  0       |  0\n c3   | integer       |  0      |             |  0       |  0\n`))\n\t\t\t\tm.noIndexes(\"users\")\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(fksQuery, \"users\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n id |   from    | to | table  | on_update   | on_delete   \n----+-----------+-------------+-------------+-----------\n 0  | c1        | id | t2     |  NO ACTION  | CASCADE\n 0  | c2        | c1 | t2     |  NO ACTION  | CASCADE\n 1  | c2        | c1 | users  |  NO ACTION  | CASCADE\n`))\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\tfks := []*schema.ForeignKey{\n\t\t\t\t\t{Symbol: \"c1_c2_fk\", Table: t, OnUpdate: schema.NoAction, OnDelete: schema.Cascade, RefTable: &schema.Table{Name: \"t2\", Schema: &schema.Schema{Name: \"main\"}}, RefColumns: []*schema.Column{{Name: \"id\"}, {Name: \"c1\"}}},\n\t\t\t\t\t{Symbol: \"c2_fk\", Table: t, OnUpdate: schema.NoAction, OnDelete: schema.Cascade, RefTable: t},\n\t\t\t\t}\n\t\t\t\tcolumns := []*schema.Column{\n\t\t\t\t\t{Name: \"c1\", Type: &schema.ColumnType{Null: true, Type: &schema.IntegerType{T: \"int\"}, Raw: \"int\"}, ForeignKeys: fks[:1]},\n\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Raw: \"integer\"}, ForeignKeys: fks},\n\t\t\t\t\t{Name: \"c3\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}, Raw: \"integer\"}},\n\t\t\t\t}\n\t\t\t\tfks[0].Columns = columns[:2]\n\t\t\t\tfks[1].Columns = columns[1:2]\n\t\t\t\tfks[1].RefColumns = columns[:1]\n\t\t\t\tchecks := []schema.Attr{\n\t\t\t\t\t&schema.Check{Expr: \"(c1 > 10)\"},\n\t\t\t\t\t&schema.Check{Name: \"ck1\", Expr: \"((c1 + c2) % 2 = 0)\"},\n\t\t\t\t\t&schema.Check{Name: \"id_nonzero\", Expr: \"(id <> 0)\"},\n\t\t\t\t}\n\t\t\t\trequire.Equal(t.Columns, columns)\n\t\t\t\trequire.Equal(t.ForeignKeys, fks)\n\t\t\t\trequire.Equal(t.Attrs[1:], checks)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"table options\",\n\t\t\tbefore: func(m mock) {\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(databasesQueryArgs, \"?\"))).\n\t\t\t\t\tWithArgs(\"main\").\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n name |   file\n------+-----------\n main |\n`))\n\t\t\t\trows := sqlmock.NewRows([]string{\"name\", \"sql\", \"wr\", \"strict\"})\n\t\t\t\trows.AddRow(\"users\", \"CREATE TABLE users(id INTEGER PRIMARY KEY) without rowid, strict\", 1, 1)\n\t\t\t\tm.ExpectQuery(sqltest.Escape(tablesQuery + \" AND sqlite_master.name IN (?)\")).\n\t\t\t\t\tWithArgs(\"users\").\n\t\t\t\t\tWillReturnRows(rows)\n\t\t\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(columnsQuery, \"users\"))).\n\t\t\t\t\tWillReturnRows(sqltest.Rows(`\n name |   type       | nullable | dflt_value  | primary  | hidden\n------+--------------+----------+ ------------+----------+----------\n id   | int          |  0       |             |  1       |  0\n`))\n\t\t\t\tm.noIndexes(\"users\")\n\t\t\t\tm.noFKs(\"users\")\n\t\t\t},\n\t\t\texpect: func(require *require.Assertions, t *schema.Table, err error) {\n\t\t\t\trequire.NoError(err)\n\t\t\t\trequire.Len(t.Attrs, 3)\n\t\t\t\trequire.Equal(t.Attrs[1], &WithoutRowID{})\n\t\t\t\trequire.Equal(t.Attrs[2], &Strict{})\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tdb, m, err := sqlmock.New()\n\t\t\trequire.NoError(t, err)\n\t\t\tmk := mock{m}\n\t\t\tdrv, err := Open(db)\n\t\t\trequire.NoError(t, err)\n\t\t\ttt.before(mk)\n\t\t\ts, err := drv.InspectSchema(context.Background(), \"\", &schema.InspectOptions{\n\t\t\t\tTables: []string{\"users\"},\n\t\t\t\tMode:   ^schema.InspectViews,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\ttt.expect(require.New(t), s.Tables[0], err)\n\t\t})\n\t}\n}\n\nfunc TestRegex_TableFK(t *testing.T) {\n\ttests := []struct {\n\t\tinput   string\n\t\tmatches []string\n\t}{\n\t\t{\n\t\t\tinput:   `CREATE TABLE pets (id int NOT NULL, owner_id int, CONSTRAINT \"owner_fk\" FOREIGN KEY(owner_id) REFERENCES users(id))`,\n\t\t\tmatches: []string{\"owner_fk\", \"owner_id\", \"users\", \"id\"},\n\t\t},\n\t\t{\n\t\t\tinput:   `CREATE TABLE pets (id int NOT NULL, owner_id int, CONSTRAINT \"owner_fk\" FOREIGN KEY (owner_id) REFERENCES users(id))`,\n\t\t\tmatches: []string{\"owner_fk\", \"owner_id\", \"users\", \"id\"},\n\t\t},\n\t\t{\n\t\t\tinput: `\nCREATE TABLE pets (\nid int NOT NULL,\nowner_id int,\nCONSTRAINT owner_fk\n\tFOREIGN KEY (\"owner_id\") REFERENCES \"users\" (id)\n)`,\n\t\t\tmatches: []string{\"owner_fk\", `\"owner_id\"`, \"users\", \"id\"},\n\t\t},\n\t\t{\n\t\t\tinput: `\nCREATE TABLE pets (\nid int NOT NULL,\nc int,\nd int,\nCONSTRAINT \"c_d_fk\" FOREIGN KEY (c, d) REFERENCES \"users\" (a, b)\n)`,\n\t\t\tmatches: []string{\"c_d_fk\", \"c, d\", \"users\", \"a, b\"},\n\t\t},\n\t\t{\n\t\t\tinput:   `CREATE TABLE pets (id int NOT NULL,c int,d int,CONSTRAINT \"c_d_fk\" FOREIGN KEY (c, \"d\") REFERENCES \"users\" (a, \"b\"))`,\n\t\t\tmatches: []string{\"c_d_fk\", `c, \"d\"`, \"users\", `a, \"b\"`},\n\t\t},\n\t\t{\n\t\t\tinput: `CREATE TABLE pets (id int NOT NULL,c int,d int,CONSTRAINT FOREIGN KEY (c, \"d\") REFERENCES \"users\" (a, \"b\"))`,\n\t\t},\n\t\t{\n\t\t\tinput: `CREATE TABLE pets (id int NOT NULL,c int,d int,CONSTRAINT name FOREIGN KEY c REFERENCES \"users\" (a, \"b\"))`,\n\t\t},\n\t\t{\n\t\t\tinput: `CREATE TABLE pets (id int NOT NULL,c int,d int,CONSTRAINT name FOREIGN KEY c REFERENCES (a, \"b\"))`,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tm := reFKT.FindStringSubmatch(tt.input)\n\t\trequire.Equal(t, len(m) != 0, len(tt.matches) != 0)\n\t\tif len(m) > 0 {\n\t\t\trequire.Equal(t, tt.matches, m[1:])\n\t\t}\n\t}\n}\n\nfunc TestRegex_ColumnFK(t *testing.T) {\n\ttests := []struct {\n\t\tinput   string\n\t\tmatches []string\n\t}{\n\t\t{\n\t\t\tinput:   `CREATE TABLE pets (id int NOT NULL, owner_id int CONSTRAINT \"owner_fk\" REFERENCES users(id))`,\n\t\t\tmatches: []string{\"owner_id\", \"owner_fk\", \"users\", \"id\"},\n\t\t},\n\t\t{\n\t\t\tinput:   `CREATE TABLE pets (id int NOT NULL, owner_id int CONSTRAINT \"owner_fk\" REFERENCES users(id))`,\n\t\t\tmatches: []string{\"owner_id\", \"owner_fk\", \"users\", \"id\"},\n\t\t},\n\t\t{\n\t\t\tinput: `\nCREATE TABLE pets (\n\tid int NOT NULL,\n\tc int REFERENCES users(id),\n\td int CONSTRAINT \"dfk\" REFERENCES users(id)\n)`,\n\t\t\tmatches: []string{\"d\", \"dfk\", \"users\", \"id\"},\n\t\t},\n\t\t{\n\t\t\tinput: `\nCREATE TABLE t1 (\n\tc int REFERENCES users(id),\n\td text CONSTRAINT \"dfk\" CHECK (d <> '') REFERENCES t2(d)\n)`,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tm := reFKC.FindStringSubmatch(tt.input)\n\t\trequire.Equal(t, len(m) != 0, len(tt.matches) != 0)\n\t\tif len(m) > 0 {\n\t\t\trequire.Equal(t, tt.matches, m[1:])\n\t\t}\n\t}\n}\n\nfunc TestRegex_Checks(t *testing.T) {\n\ttests := []struct {\n\t\tinput  string\n\t\tchecks []*schema.Check\n\t}{\n\t\t{\n\t\t\tinput: `CREATE TABLE pets (id int NOT NULL, owner_id int CONSTRAINT \"ck1\" CHECK (owner_id <> 0))`,\n\t\t\tchecks: []*schema.Check{\n\t\t\t\t{Name: \"ck1\", Expr: \"(owner_id <> 0)\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: `CREATE TABLE pets (id int NOT NULL, owner_id int CHECK (owner_id <> 0) CONSTRAINT \"ck1\")`,\n\t\t\tchecks: []*schema.Check{\n\t\t\t\t{Expr: \"(owner_id <> 0)\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: `CREATE TABLE pets (id int NOT NULL CHECK (\"id\" <> 0), owner_id int CONSTRAINT \"ck1\" CHECK ((owner_id) <> 0))`,\n\t\t\tchecks: []*schema.Check{\n\t\t\t\t{Expr: `(\"id\" <> 0)`},\n\t\t\t\t{Name: \"ck1\", Expr: \"((owner_id) <> 0)\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: `CREATE TABLE pets (id int NOT NULL CHECK (\"(\" <> ')'), owner_id int CONSTRAINT \"ck1\" CHECK ((owner_id) <> 0))`,\n\t\t\tchecks: []*schema.Check{\n\t\t\t\t{Expr: `(\"(\" <> ')')`},\n\t\t\t\t{Name: \"ck1\", Expr: \"((owner_id) <> 0)\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: \"CREATE TABLE pets (\\n\\tid int NOT NULL CHECK (id <> 0) CHECK ((id % 2) = 0)\\n,\\n\\towner_id int CHECK ((owner_id) <> 0)\\n)\",\n\t\t\tchecks: []*schema.Check{\n\t\t\t\t{Expr: \"(id <> 0)\"},\n\t\t\t\t{Expr: \"((id % 2) = 0)\"},\n\t\t\t\t{Expr: \"((owner_id) <> 0)\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: `CREATE TABLE t1(\n\t\t\t\tx INTEGER CHECK( x<5 ),\n\t\t\t\ty REAL CHECK( y>x ))`,\n\t\t\tchecks: []*schema.Check{\n\t\t\t\t{Expr: \"( x<5 )\"},\n\t\t\t\t{Expr: \"( y>x )\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: `CREATE TABLE t(\n\t\t\t\tx INTEGER CONSTRAINT one CHECK( typeof(coalesce(x,0))==\"integer\" ),\n\t\t\t\ty NUMERIC CONSTRAINT two CHECK( typeof(coalesce(y,0.1))=='real' ),\n\t\t\t\tz TEXT CONSTRAINT three CHECK( typeof(coalesce(z,''))=='text' )\n\t\t\t)`,\n\t\t\tchecks: []*schema.Check{\n\t\t\t\t{Name: \"one\", Expr: `( typeof(coalesce(x,0))==\"integer\" )`},\n\t\t\t\t{Name: \"two\", Expr: `( typeof(coalesce(y,0.1))=='real' )`},\n\t\t\t\t{Name: \"three\", Expr: `( typeof(coalesce(z,''))=='text' )`},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tinput: `CREATE TABLE t(\n\t\t\t\tx char check ('foo''(' <> 1)\n\t\t\t)`,\n\t\t\tchecks: []*schema.Check{\n\t\t\t\t{Expr: `('foo''(' <> 1)`},\n\t\t\t},\n\t\t},\n\t\t// Invalid inputs.\n\t\t{\n\t\t\tinput: \"CREATE TABLE t(x char check)\",\n\t\t},\n\t\t{\n\t\t\tinput: \"CREATE TABLE t(x char constraint x check)\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tconst name = \"users\"\n\t\tdb, m, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\t\tmk := mock{m}\n\t\tmk.tableExists(name, true, tt.input)\n\t\tmk.noColumns(name)\n\t\tmk.noIndexes(name)\n\t\tmk.noFKs(name)\n\t\tdrv, err := Open(db)\n\t\trequire.NoError(t, err)\n\t\ts, err := drv.InspectSchema(context.Background(), \"\", &schema.InspectOptions{\n\t\t\tTables: []string{name},\n\t\t\tMode:   ^schema.InspectViews,\n\t\t})\n\t\trequire.NoError(t, err)\n\t\ttable := s.Tables[0]\n\t\trequire.Equal(t, len(table.Attrs[1:]), len(tt.checks))\n\t\tfor i := range tt.checks {\n\t\t\trequire.Equal(t, tt.checks[i], table.Attrs[i+1])\n\t\t}\n\t}\n}\n\nfunc TestRegex_GeneratedExpr(t *testing.T) {\n\ttests := []struct {\n\t\tinput  string\n\t\tcolumn *schema.Column\n\t}{\n\t\t{\n\t\t\tinput: \"CREATE TABLE t1( a NOT NULL DEFAULT 'aaa', b AS(c) NOT NULL, c NOT NULL DEFAULT 'ccc');\",\n\t\t\tcolumn: schema.NewColumn(\"b\").\n\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"(c)\", Type: \"VIRTUAL\"}),\n\t\t},\n\t\t{\n\t\t\tinput: \"CREATE TABLE t4(a NOT NULL DEFAULT 123, b AS(a*10+4) STORED UNIQUE);\",\n\t\t\tcolumn: schema.NewColumn(\"b\").\n\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"(a*10+4)\", Type: \"VIRTUAL\"}),\n\t\t},\n\t\t{\n\t\t\tinput: \"CREATE TABLE t1(aa , bb AS (17) UNIQUE);\",\n\t\t\tcolumn: schema.NewColumn(\"bb\").\n\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"(17)\", Type: \"VIRTUAL\"}),\n\t\t},\n\t\t{\n\t\t\tinput: \"CREATE TABLE t1( a integer primary key, b int generated always as (a+5), c text GENERATED   ALWAYS as (printf('%08x',a)));\",\n\t\t\tcolumn: schema.NewColumn(\"c\").\n\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"(printf('%08x',a))\", Type: \"VIRTUAL\"}),\n\t\t},\n\t\t{\n\t\t\tinput: \"CREATE TABLE t1( a integer primary key, b int generated always as (a+5), c text GENERATED   ALWAYS as (printf('%08x',a)), d Generated\\nAlways\\nAS\\n('xy\\\\()zzy'));\",\n\t\t\tcolumn: schema.NewColumn(\"d\").\n\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"('xy\\\\()zzy')\", Type: \"VIRTUAL\"}),\n\t\t},\n\t\t{\n\t\t\tinput: \"CREATE TABLE t0( c0 AS (('a', 9) < ('b', c1)), c1 AS (1), c2 CHECK (1 = c1) );\",\n\t\t\tcolumn: schema.NewColumn(\"c0\").\n\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"(('a', 9) < ('b', c1))\", Type: \"VIRTUAL\"}),\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tconst name = \"users\"\n\t\tdb, m, err := sqlmock.New()\n\t\trequire.NoError(t, err)\n\t\tmk := mock{m}\n\t\tmk.tableExists(name, true, tt.input)\n\t\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(columnsQuery, name))).\n\t\t\tWillReturnRows(sqltest.Rows(fmt.Sprintf(`\n name |   type       | nullable | dflt_value  | primary  | hidden\n------+--------------+----------+ ------------+----------+----------\n %s   | int           |  1      |     a       |  0       |  2\n`, tt.column.Name)))\n\t\tmk.noIndexes(name)\n\t\tmk.noFKs(name)\n\t\tdrv, err := Open(db)\n\t\trequire.NoError(t, err)\n\t\ts, err := drv.InspectSchema(context.Background(), \"\", &schema.InspectOptions{\n\t\t\tTables: []string{name},\n\t\t\tMode:   ^schema.InspectViews,\n\t\t})\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, tt.column.Attrs, s.Tables[0].Columns[0].Attrs)\n\t}\n}\n\ntype mock struct {\n\tsqlmock.Sqlmock\n}\n\nfunc (m mock) tableExists(table string, exists bool, stmt ...string) {\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(databasesQueryArgs, \"?\"))).\n\t\tWithArgs(\"main\").\n\t\tWillReturnRows(sqltest.Rows(`\n name |   file    \n------+-----------\n main |   \n`))\n\trows := sqlmock.NewRows([]string{\"name\", \"sql\", \"wr\", \"strict\"})\n\tif exists {\n\t\trows.AddRow(table, stmt[0], nil, nil)\n\t}\n\tm.ExpectQuery(sqltest.Escape(tablesQuery + \" AND sqlite_master.name IN (?)\")).\n\t\tWithArgs(table).\n\t\tWillReturnRows(rows)\n}\n\nfunc (m mock) noColumns(table string) {\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(columnsQuery, table))).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"name\", \"type\", \"nullable\", \"dflt_value\", \"primary\"}))\n}\n\nfunc (m mock) noIndexes(table string) {\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexesQuery, table))).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"name\", \"unique\", \"origin\", \"partial\", \"sql\"}))\n}\n\nfunc (m mock) noFKs(table string) {\n\tm.ExpectQuery(sqltest.Escape(fmt.Sprintf(fksQuery, table))).\n\t\tWillReturnRows(sqlmock.NewRows([]string{\"id\", \"from\", \"to\", \"table\", \"on_update\", \"on_delete\"}))\n}\n"
  },
  {
    "path": "sql/sqlite/migrate.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n)\n\n// DefaultPlan provides basic planning capabilities for SQLite dialects.\n// Note, it is recommended to call Open, create a new Driver and use its\n// migrate.PlanApplier when a database connection is available.\nvar DefaultPlan migrate.PlanApplier = &planApply{conn: &conn{ExecQuerier: sqlx.NoRows}}\n\n// A planApply provides migration capabilities for schema elements.\ntype planApply struct{ *conn }\n\n// PlanChanges returns a migration plan for the given schema changes.\nfunc (p *planApply) PlanChanges(ctx context.Context, name string, changes []schema.Change, opts ...migrate.PlanOption) (*migrate.Plan, error) {\n\ts := &state{\n\t\tconn: p.conn,\n\t\tPlan: migrate.Plan{\n\t\t\tName:          name,\n\t\t\tTransactional: true,\n\t\t},\n\t\tPlanOptions: migrate.PlanOptions{\n\t\t\t// Currently, the driver does not support attached\n\t\t\t// schemas and assumed the connected schema is \"main\".\n\t\t\tSchemaQualifier: new(string),\n\t\t},\n\t}\n\tfor _, o := range opts {\n\t\to(&s.PlanOptions)\n\t}\n\tif err := verifyChanges(ctx, changes); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := s.plan(ctx, changes); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := sqlx.SetReversible(&s.Plan); err != nil {\n\t\treturn nil, err\n\t}\n\t// Disable foreign-keys enforcement if it is required\n\t// by one of the changes in the plan.\n\tif s.skipFKs {\n\t\t// Callers should note that these 2 pragmas are no-op in transactions,\n\t\t// See: https://sqlite.org/pragma.html#pragma_foreign_keys.\n\t\ts.Changes = append([]*migrate.Change{{Cmd: \"PRAGMA foreign_keys = off\", Comment: \"disable the enforcement of foreign-keys constraints\"}}, s.Changes...)\n\t\ts.append(&migrate.Change{Cmd: \"PRAGMA foreign_keys = on\", Comment: \"enable back the enforcement of foreign-keys constraints\"})\n\t}\n\treturn &s.Plan, nil\n}\n\n// ApplyChanges applies the changes on the database. An error is returned\n// if the driver is unable to produce a plan to it, or one of the statements\n// is failed or unsupported.\nfunc (p *planApply) ApplyChanges(ctx context.Context, changes []schema.Change, opts ...migrate.PlanOption) error {\n\treturn sqlx.ApplyChanges(ctx, changes, p, opts...)\n}\n\n// state represents the state of a planning. It's not part of\n// planApply so that multiple planning/applying can be called\n// in parallel.\ntype state struct {\n\t*conn\n\tmigrate.Plan\n\tmigrate.PlanOptions\n\tskipFKs bool\n}\n\n// Exec executes the changes on the database. An error is returned\n// if one of the operations fail, or a change is not supported.\nfunc (s *state) plan(ctx context.Context, changes []schema.Change) (err error) {\n\tfor _, c := range changes {\n\t\tswitch c := c.(type) {\n\t\tcase *schema.AddTable:\n\t\t\terr = s.addTable(ctx, c)\n\t\tcase *schema.DropTable:\n\t\t\terr = s.dropTable(ctx, c)\n\t\tcase *schema.ModifyTable:\n\t\t\terr = s.modifyTable(ctx, c)\n\t\tcase *schema.RenameTable:\n\t\t\ts.renameTable(c)\n\t\tcase *schema.AddView:\n\t\t\terr = s.addView(c)\n\t\tcase *schema.DropView:\n\t\t\terr = s.dropView(c)\n\t\tcase *schema.ModifyView:\n\t\t\terr = s.modifyView(c)\n\t\tcase *schema.RenameView:\n\t\t\terr = s.renameView(c)\n\t\tcase *schema.AddTrigger:\n\t\t\terr = s.addTrigger(c)\n\t\tcase *schema.DropTrigger:\n\t\t\terr = s.dropTrigger(c)\n\t\tdefault:\n\t\t\terr = fmt.Errorf(\"unsupported change %T\", c)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// addTable builds and executes the query for creating a table in a schema.\nfunc (s *state) addTable(ctx context.Context, add *schema.AddTable) error {\n\tvar (\n\t\terrs []string\n\t\tb    = s.Build(\"CREATE TABLE\").Table(add.T)\n\t)\n\tif sqlx.Has(add.Extra, &schema.IfNotExists{}) {\n\t\tb.P(\"IF NOT EXISTS\")\n\t}\n\tb.WrapIndent(func(b *sqlx.Builder) {\n\t\tb.MapIndent(add.T.Columns, func(i int, b *sqlx.Builder) {\n\t\t\tif err := s.column(b, add.T.Columns[i]); err != nil {\n\t\t\t\terrs = append(errs, err.Error())\n\t\t\t}\n\t\t})\n\t\t// Primary keys with auto-increment are inlined on the column definition.\n\t\tif pk := add.T.PrimaryKey; pk != nil && !autoincPK(pk) {\n\t\t\tb.Comma().NL().P(\"PRIMARY KEY\")\n\t\t\ts.indexParts(b, pk.Parts)\n\t\t}\n\t\tif len(add.T.ForeignKeys) > 0 {\n\t\t\tb.Comma()\n\t\t\ts.fks(b, add.T.ForeignKeys...)\n\t\t}\n\t\tfor _, attr := range add.T.Attrs {\n\t\t\tif c, ok := attr.(*schema.Check); ok {\n\t\t\t\tb.Comma().NL()\n\t\t\t\tcheck(b, c)\n\t\t\t}\n\t\t}\n\t})\n\tif len(errs) > 0 {\n\t\treturn fmt.Errorf(\"create table %q: %s\", add.T.Name, strings.Join(errs, \", \"))\n\t}\n\tvar options []string\n\tif sqlx.Has(add.T.Attrs, &WithoutRowID{}) {\n\t\toptions = append(options, \"WITHOUT ROWID\")\n\t}\n\tif sqlx.Has(add.T.Attrs, &Strict{}) {\n\t\toptions = append(options, \"STRICT\")\n\t}\n\tb.MapComma(options, func(i int, b *sqlx.Builder) {\n\t\tb.P(options[i])\n\t})\n\ts.append(&migrate.Change{\n\t\tCmd:     b.String(),\n\t\tSource:  add,\n\t\tReverse: s.Build(\"DROP TABLE\").Table(add.T).String(),\n\t\tComment: fmt.Sprintf(\"create %q table\", add.T.Name),\n\t})\n\tif err := s.tableSeq(ctx, add); err != nil {\n\t\treturn err\n\t}\n\treturn s.addIndexes(add.T, add.T.Indexes...)\n}\n\n// dropTable builds and executes the query for dropping a table from a schema.\nfunc (s *state) dropTable(ctx context.Context, drop *schema.DropTable) error {\n\trs := &state{conn: s.conn, PlanOptions: s.PlanOptions}\n\tif err := rs.addTable(ctx, &schema.AddTable{T: drop.T}); err != nil {\n\t\treturn fmt.Errorf(\"calculate reverse for drop table %q: %w\", drop.T.Name, err)\n\t}\n\ts.skipFKs = true\n\tb := s.Build(\"DROP TABLE\")\n\tif sqlx.Has(drop.Extra, &schema.IfExists{}) {\n\t\tb.P(\"IF EXISTS\")\n\t}\n\tb.Ident(drop.T.Name)\n\ts.append(&migrate.Change{\n\t\tCmd:     b.String(),\n\t\tSource:  drop,\n\t\tComment: fmt.Sprintf(\"drop %q table\", drop.T.Name),\n\t\t// The reverse of 'DROP TABLE' might be a multi\n\t\t// statement operation. e.g., table with indexes.\n\t\tReverse: func() any {\n\t\t\tcmd := make([]string, len(rs.Changes))\n\t\t\tfor i, c := range rs.Changes {\n\t\t\t\tcmd[i] = c.Cmd\n\t\t\t}\n\t\t\tif len(cmd) == 1 {\n\t\t\t\treturn cmd[0]\n\t\t\t}\n\t\t\treturn cmd\n\t\t}(),\n\t})\n\treturn nil\n}\n\n// modifyTable builds and executes the queries for bringing the table into its modified state.\n// If the modification contains changes that are not index creation/deletion or a simple column\n// addition, the changes are applied using a temporary table following the procedure mentioned\n// in: https://www.sqlite.org/lang_altertable.html#making_other_kinds_of_table_schema_changes.\nfunc (s *state) modifyTable(ctx context.Context, modify *schema.ModifyTable) error {\n\tif alterable(modify) {\n\t\treturn s.alterTable(modify)\n\t}\n\ts.skipFKs = true\n\tnewT := *modify.T\n\tindexes := newT.Indexes\n\tnewT.Indexes = nil\n\tnewT.Name = \"new_\" + newT.Name\n\t// Create a new table with a temporary name, and copy the existing rows to it.\n\tif err := s.addTable(ctx, &schema.AddTable{T: &newT}); err != nil {\n\t\treturn err\n\t}\n\tcopied, err := s.copyRows(modify.T, &newT, modify.Changes)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Drop the current table, and rename the new one to its real name.\n\ts.append(&migrate.Change{\n\t\tCmd:    s.Build(\"DROP TABLE\").Ident(modify.T.Name).String(),\n\t\tSource: modify,\n\t\tComment: fmt.Sprintf(\"drop %q table %s\", modify.T.Name, func() string {\n\t\t\tif copied {\n\t\t\t\treturn \"after copying rows\"\n\t\t\t}\n\t\t\treturn \"without copying rows (no columns)\"\n\t\t}()),\n\t})\n\ts.append(&migrate.Change{\n\t\tCmd:     s.Build(\"ALTER TABLE\").Ident(newT.Name).P(\"RENAME TO\").Ident(modify.T.Name).String(),\n\t\tSource:  modify,\n\t\tComment: fmt.Sprintf(\"rename temporary table %q to %q\", newT.Name, modify.T.Name),\n\t})\n\treturn s.addIndexes(modify.T, indexes...)\n}\n\nfunc (s *state) renameTable(c *schema.RenameTable) {\n\ts.append(&migrate.Change{\n\t\tSource:  c,\n\t\tComment: fmt.Sprintf(\"rename a table from %q to %q\", c.From.Name, c.To.Name),\n\t\tCmd:     s.Build(\"ALTER TABLE\").Table(c.From).P(\"RENAME TO\").Table(c.To).String(),\n\t\tReverse: s.Build(\"ALTER TABLE\").Table(c.To).P(\"RENAME TO\").Table(c.From).String(),\n\t})\n}\n\nfunc (s *state) column(b *sqlx.Builder, c *schema.Column) error {\n\tt, err := FormatType(c.Type.Type)\n\tif err != nil {\n\t\treturn err\n\t}\n\tb.Ident(c.Name).P(t)\n\tif !c.Type.Null {\n\t\tb.P(\"NOT\")\n\t}\n\tb.P(\"NULL\")\n\tif c.Default != nil {\n\t\tx, err := defaultValue(c)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tb.P(\"DEFAULT\", x)\n\t}\n\tswitch hasA, hasX := sqlx.Has(c.Attrs, &AutoIncrement{}), sqlx.Has(c.Attrs, &schema.GeneratedExpr{}); {\n\tcase hasA && hasX:\n\t\treturn fmt.Errorf(\"both autoincrement and generation expression specified for column %q\", c.Name)\n\tcase hasA:\n\t\tb.P(\"PRIMARY KEY AUTOINCREMENT\")\n\tcase hasX:\n\t\tx := &schema.GeneratedExpr{}\n\t\tsqlx.Has(c.Attrs, x)\n\t\tb.P(\"AS\", sqlx.MayWrap(x.Expr), x.Type)\n\t}\n\treturn nil\n}\n\nfunc (s *state) dropIndexes(t *schema.Table, indexes ...*schema.Index) error {\n\trs := &state{conn: s.conn}\n\tif err := rs.addIndexes(t, indexes...); err != nil {\n\t\treturn err\n\t}\n\tfor i := range rs.Changes {\n\t\ts.append(&migrate.Change{\n\t\t\tCmd:     rs.Changes[i].Reverse.(string),\n\t\t\tReverse: rs.Changes[i].Cmd,\n\t\t\tComment: fmt.Sprintf(\"drop index %q from table: %q\", indexes[i].Name, t.Name),\n\t\t})\n\t}\n\treturn nil\n}\n\nfunc (s *state) addIndexes(t *schema.Table, indexes ...*schema.Index) error {\n\tfor _, idx := range indexes {\n\t\tif err := normalizeIdxName(idx, t); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tb := s.Build(\"CREATE\")\n\t\tif idx.Unique {\n\t\t\tb.P(\"UNIQUE\")\n\t\t}\n\t\tb.P(\"INDEX\")\n\t\tif idx.Name != \"\" {\n\t\t\tb.Ident(idx.Name)\n\t\t}\n\t\tb.P(\"ON\").Ident(t.Name)\n\t\ts.indexParts(b, idx.Parts)\n\t\tif p := (IndexPredicate{}); sqlx.Has(idx.Attrs, &p) {\n\t\t\tb.P(\"WHERE\").P(p.P)\n\t\t}\n\t\ts.append(&migrate.Change{\n\t\t\tCmd:     b.String(),\n\t\t\tSource:  &schema.AddIndex{I: idx},\n\t\t\tReverse: s.Build(\"DROP INDEX\").Ident(idx.Name).String(),\n\t\t\tComment: fmt.Sprintf(\"create index %q to table: %q\", idx.Name, t.Name),\n\t\t})\n\t}\n\treturn nil\n}\n\n// normalizeIdxName normalizes the index name before generating the CREATE INDEX statement.\nfunc normalizeIdxName(idx *schema.Index, t *schema.Table) error {\n\t// PRIMARY KEY or UNIQUE columns automatically create indexes with the generated name.\n\t// See: sqlite/build.c#sqlite3CreateIndex. Therefore, we ignore such PKs, but create\n\t// the inlined UNIQUE constraints manually with custom name, because SQLite does not\n\t// allow creating indexes with such names manually. Note, this case is possible if\n\t// \"apply\" schema that was inspected from the database as-is.\n\tif strings.HasPrefix(idx.Name, \"sqlite_autoindex\") {\n\t\tif i := (IndexOrigin{}); sqlx.Has(idx.Attrs, &i) && i.O == \"p\" {\n\t\t\treturn nil\n\t\t}\n\t\t// Use the following format: <Table>_<Columns>.\n\t\tnames := make([]string, len(idx.Parts)+1)\n\t\tnames[0] = t.Name\n\t\tfor i, p := range idx.Parts {\n\t\t\tif p.C == nil {\n\t\t\t\treturn fmt.Errorf(\"unexpected index part %s (%d)\", idx.Name, i)\n\t\t\t}\n\t\t\tnames[i+1] = p.C.Name\n\t\t}\n\t\tidx.Name = strings.Join(names, \"_\")\n\t}\n\treturn nil\n}\n\nfunc (s *state) indexParts(b *sqlx.Builder, parts []*schema.IndexPart) {\n\tb.Wrap(func(b *sqlx.Builder) {\n\t\tb.MapComma(parts, func(i int, b *sqlx.Builder) {\n\t\t\tswitch part := parts[i]; {\n\t\t\tcase part.C != nil:\n\t\t\t\tb.Ident(part.C.Name)\n\t\t\tcase part.X != nil:\n\t\t\t\tb.WriteString(sqlx.MayWrap(part.X.(*schema.RawExpr).X))\n\t\t\t}\n\t\t\tif parts[i].Desc {\n\t\t\t\tb.P(\"DESC\")\n\t\t\t}\n\t\t})\n\t})\n}\n\nfunc (s *state) fks(b *sqlx.Builder, fks ...*schema.ForeignKey) {\n\tb.MapIndent(fks, func(i int, b *sqlx.Builder) {\n\t\tfk := fks[i]\n\t\tif fk.Symbol != \"\" {\n\t\t\tb.P(\"CONSTRAINT\").Ident(fk.Symbol)\n\t\t}\n\t\tb.P(\"FOREIGN KEY\")\n\t\tb.Wrap(func(b *sqlx.Builder) {\n\t\t\tb.MapComma(fk.Columns, func(i int, b *sqlx.Builder) {\n\t\t\t\tb.Ident(fk.Columns[i].Name)\n\t\t\t})\n\t\t})\n\t\tb.P(\"REFERENCES\").Ident(fk.RefTable.Name)\n\t\tb.Wrap(func(b *sqlx.Builder) {\n\t\t\tb.MapComma(fk.RefColumns, func(i int, b *sqlx.Builder) {\n\t\t\t\tb.Ident(fk.RefColumns[i].Name)\n\t\t\t})\n\t\t})\n\t\tif fk.OnUpdate != \"\" {\n\t\t\tb.P(\"ON UPDATE\", string(fk.OnUpdate))\n\t\t}\n\t\tif fk.OnDelete != \"\" {\n\t\t\tb.P(\"ON DELETE\", string(fk.OnDelete))\n\t\t}\n\t})\n}\n\nfunc (s *state) copyRows(from *schema.Table, to *schema.Table, changes []schema.Change) (bool, error) {\n\tvar fromC, toC []string\n\tfor _, column := range to.Columns {\n\t\t// Skip generated columns in INSERT as they are computed.\n\t\tif sqlx.Has(column.Attrs, &schema.GeneratedExpr{}) {\n\t\t\tcontinue\n\t\t}\n\t\t// Find a change that associated with this column, if exists.\n\t\tvar change schema.Change\n\t\tfor i := range changes {\n\t\t\tswitch c := changes[i].(type) {\n\t\t\tcase *schema.AddColumn:\n\t\t\t\tif c.C.Name != column.Name {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif change != nil {\n\t\t\t\t\treturn false, fmt.Errorf(\"duplicate changes for column: %q: %T, %T\", column.Name, change, c)\n\t\t\t\t}\n\t\t\t\tchange = changes[i]\n\t\t\tcase *schema.ModifyColumn:\n\t\t\t\tif c.To.Name != column.Name {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif change != nil {\n\t\t\t\t\treturn false, fmt.Errorf(\"duplicate changes for column: %q: %T, %T\", column.Name, change, c)\n\t\t\t\t}\n\t\t\t\tchange = changes[i]\n\t\t\tcase *schema.RenameColumn:\n\t\t\t\tif c.To.Name != column.Name {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif change != nil {\n\t\t\t\t\treturn false, fmt.Errorf(\"duplicate changes for column: %q: %T, %T\", column.Name, change, c)\n\t\t\t\t}\n\t\t\t\tchange = changes[i]\n\t\t\tcase *schema.DropColumn:\n\t\t\t\tif c.C.Name == column.Name {\n\t\t\t\t\treturn false, fmt.Errorf(\"unexpected drop column: %q\", column.Name)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tswitch change := change.(type) {\n\t\t// We expect that new columns are added with DEFAULT/GENERATED\n\t\t// values or defined as nullable if the table is not empty.\n\t\tcase *schema.AddColumn:\n\t\t// Column modification requires special handling if it was\n\t\t// converted from nullable to non-nullable with default value.\n\t\tcase *schema.ModifyColumn:\n\t\t\ttoC = append(toC, column.Name)\n\t\t\tif !column.Type.Null && column.Default != nil && change.Change.Is(schema.ChangeNull|schema.ChangeDefault) {\n\t\t\t\tx, err := defaultValue(column)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn false, err\n\t\t\t\t}\n\t\t\t\tfromC = append(fromC, fmt.Sprintf(\"IFNULL(`%[1]s`, %s) AS `%[1]s`\", column.Name, x))\n\t\t\t} else {\n\t\t\t\tfromC = append(fromC, column.Name)\n\t\t\t}\n\t\tcase *schema.RenameColumn:\n\t\t\ttoC = append(toC, change.To.Name)\n\t\t\tfromC = append(fromC, change.From.Name)\n\t\t// Columns without changes should be transferred as-is.\n\t\tcase nil:\n\t\t\ttoC = append(toC, column.Name)\n\t\t\tfromC = append(fromC, column.Name)\n\t\t}\n\t}\n\tinsert := len(toC) > 0\n\tif insert {\n\t\ts.append(&migrate.Change{\n\t\t\tCmd: fmt.Sprintf(\n\t\t\t\t\"INSERT INTO `%s` (%s) SELECT %s FROM `%s`\",\n\t\t\t\tto.Name, identComma(toC), identComma(fromC), from.Name,\n\t\t\t),\n\t\t\tComment: fmt.Sprintf(\"copy rows from old table %q to new temporary table %q\", from.Name, to.Name),\n\t\t})\n\t}\n\treturn insert, nil\n}\n\n// alterTable alters the table with the given changes. Assuming the changes are \"alterable\".\nfunc (s *state) alterTable(modify *schema.ModifyTable) error {\n\tfor _, change := range modify.Changes {\n\t\tswitch change := change.(type) {\n\t\tcase *schema.AddIndex:\n\t\t\tif err := s.addIndexes(modify.T, change.I); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase *schema.DropIndex:\n\t\t\tif err := s.dropIndexes(modify.T, change.I); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase *schema.RenameIndex:\n\t\t\tif err := s.addIndexes(modify.T, change.To); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := s.dropIndexes(modify.T, change.From); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase *schema.AddColumn:\n\t\t\tb := s.Build(\"ALTER TABLE\").Ident(modify.T.Name)\n\t\t\tr := b.Clone()\n\t\t\tif err := s.column(b.P(\"ADD COLUMN\"), change.C); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\ts.append(&migrate.Change{\n\t\t\t\tSource:  change,\n\t\t\t\tCmd:     b.String(),\n\t\t\t\tReverse: r.P(\"DROP COLUMN\").Ident(change.C.Name).String(),\n\t\t\t\tComment: fmt.Sprintf(\"add column %q to table: %q\", change.C.Name, modify.T.Name),\n\t\t\t})\n\t\tcase *schema.RenameColumn:\n\t\t\tb := s.Build(\"ALTER TABLE\").Ident(modify.T.Name).P(\"RENAME COLUMN\")\n\t\t\tr := b.Clone()\n\t\t\ts.append(&migrate.Change{\n\t\t\t\tSource:  change,\n\t\t\t\tCmd:     b.Ident(change.From.Name).P(\"TO\").Ident(change.To.Name).String(),\n\t\t\t\tReverse: r.Ident(change.To.Name).P(\"TO\").Ident(change.From.Name).String(),\n\t\t\t\tComment: fmt.Sprintf(\"rename a column from %q to %q\", change.From.Name, change.To.Name),\n\t\t\t})\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unexpected change in alter table: %T\", change)\n\t\t}\n\t}\n\treturn nil\n}\n\n// tableSeq sets the sequence value of the table if it was provided by\n// the user on table creation.\nfunc (s *state) tableSeq(ctx context.Context, add *schema.AddTable) error {\n\tvar inc AutoIncrement\n\tswitch pk := add.T.PrimaryKey; {\n\t// Sequence was set on table attributes.\n\tcase sqlx.Has(add.T.Attrs, &inc) && inc.Seq > 0:\n\t// Sequence was set on table primary-key (a single column PK).\n\tcase pk != nil && len(pk.Parts) == 1 && pk.Parts[0].C != nil && sqlx.Has(pk.Parts[0].C.Attrs, &inc) && inc.Seq > 0:\n\tdefault:\n\t\treturn nil\n\t}\n\t// SQLite tracks the AUTOINCREMENT in the \"sqlite_sequence\" table that is created and initialized automatically\n\t// whenever the first \"PRIMARY KEY AUTOINCREMENT\" is created. However, rows in this table are populated after the\n\t// first insertion to the associated table (name, seq). Therefore, we check if the sequence table and the row exist,\n\t// and in case they are not, we insert a new non-zero sequence to it.\n\trows, err := s.QueryContext(ctx, \"SELECT seq FROM sqlite_sequence WHERE name = ?\", add.T.Name)\n\tif err != nil || !rows.Next() {\n\t\ts.append(&migrate.Change{\n\t\t\tCmd:     fmt.Sprintf(\"INSERT INTO sqlite_sequence (name, seq) VALUES (%q, %d)\", add.T.Name, inc.Seq),\n\t\t\tSource:  add,\n\t\t\tReverse: fmt.Sprintf(\"UPDATE sqlite_sequence SET seq = 0 WHERE name = %q\", add.T.Name),\n\t\t\tComment: fmt.Sprintf(\"set sequence for %q table\", add.T.Name),\n\t\t})\n\t}\n\tif rows != nil {\n\t\trows.Close()\n\t\treturn rows.Err()\n\t}\n\treturn nil\n}\n\nfunc (s *state) append(c *migrate.Change) {\n\ts.Changes = append(s.Changes, c)\n}\n\nfunc alterable(modify *schema.ModifyTable) bool {\n\tfor _, change := range modify.Changes {\n\t\tswitch change := change.(type) {\n\t\tcase *schema.RenameColumn, *schema.RenameIndex, *schema.DropIndex, *schema.AddIndex:\n\t\tcase *schema.AddColumn:\n\t\t\tif len(change.C.Indexes) > 0 || len(change.C.ForeignKeys) > 0 {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// If the column has a DEFAULT clause, it must be a constant value.\n\t\t\t// See: https://www.sqlite.org/lang_altertable.html#alter_table_add_column.\n\t\t\tswitch x := change.C.Default.(type) {\n\t\t\tcase *schema.Literal:\n\t\t\t\tif slices.Contains([]string{\"CURRENT_TIME\", \"CURRENT_DATE\", \"CURRENT_TIMESTAMP\"}, x.V) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\tcase *schema.RawExpr:\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// Only VIRTUAL generated columns can be added using ALTER TABLE.\n\t\t\tif x := (schema.GeneratedExpr{}); sqlx.Has(change.C.Attrs, &x) && storedOrVirtual(x.Type) == stored {\n\t\t\t\treturn false\n\t\t\t}\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// checks writes the CHECK constraint to the builder.\nfunc check(b *sqlx.Builder, c *schema.Check) {\n\texpr := c.Expr\n\t// Expressions should be wrapped with parens.\n\tif t := strings.TrimSpace(expr); !strings.HasPrefix(t, \"(\") || !strings.HasSuffix(t, \")\") {\n\t\texpr = \"(\" + t + \")\"\n\t}\n\tif c.Name != \"\" {\n\t\tb.P(\"CONSTRAINT\").Ident(c.Name)\n\t}\n\tb.P(\"CHECK\", expr)\n}\n\nfunc autoincPK(pk *schema.Index) bool {\n\treturn sqlx.Has(pk.Attrs, &AutoIncrement{}) ||\n\t\tlen(pk.Parts) == 1 && pk.Parts[0].C != nil && sqlx.Has(pk.Parts[0].C.Attrs, &AutoIncrement{})\n}\n\n// Build instantiates a new builder and writes the given phrase to it.\nfunc (s *state) Build(phrases ...string) *sqlx.Builder {\n\treturn (*Driver).StmtBuilder(nil, s.PlanOptions).\n\t\tP(phrases...)\n}\n\nfunc defaultValue(c *schema.Column) (string, error) {\n\tswitch x := c.Default.(type) {\n\tcase *schema.Literal:\n\t\tswitch c.Type.Type.(type) {\n\t\tcase *schema.BoolType, *schema.DecimalType, *schema.IntegerType, *schema.FloatType:\n\t\t\treturn x.V, nil\n\t\tdefault:\n\t\t\treturn sqlx.SingleQuote(x.V)\n\t\t}\n\tcase *schema.RawExpr:\n\t\treturn sqlx.MayWrap(x.X), nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unexpected default value type: %T\", x)\n\t}\n}\n\nfunc identComma(c []string) string {\n\tb := &sqlx.Builder{QuoteOpening: '`', QuoteClosing: '`'}\n\tb.MapComma(c, func(i int, b *sqlx.Builder) {\n\t\tif strings.ContainsRune(c[i], '`') {\n\t\t\tb.WriteString(c[i])\n\t\t} else {\n\t\t\tb.Ident(c[i])\n\t\t}\n\t})\n\treturn b.String()\n}\n"
  },
  {
    "path": "sql/sqlite/migrate_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/internal/sqltest\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\n\t\"github.com/DATA-DOG/go-sqlmock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestPlanChanges(t *testing.T) {\n\ttests := []struct {\n\t\tchanges []schema.Change\n\t\toptions []migrate.PlanOption\n\t\tmock    func(mock)\n\t\tplan    *migrate.Plan\n\t}{\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}},\n\t\t\t\t\t\t\t{Name: \"text\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Null: true}},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Check{Expr: \"(text <> '')\"},\n\t\t\t\t\t\t\t&schema.Check{Name: \"positive_id\", Expr: \"(id <> 0)\"},\n\t\t\t\t\t\t\t&WithoutRowID{},\n\t\t\t\t\t\t\t&Strict{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges:       []*migrate.Change{{Cmd: \"CREATE TABLE `posts` (`id` integer NOT NULL, `text` text NULL, CHECK (text <> ''), CONSTRAINT `positive_id` CHECK (id <> 0)) WITHOUT ROWID, STRICT\", Reverse: \"DROP TABLE `posts`\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{\n\t\t\t\t\tT: &schema.Table{\n\t\t\t\t\t\tName: \"posts\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"integer\"}}, Attrs: []schema.Attr{&AutoIncrement{Seq: 1024}}},\n\t\t\t\t\t\t\t{Name: \"text\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"text\"}, Null: true}},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Check{Expr: \"(text <> '')\"},\n\t\t\t\t\t\t\t&schema.Check{Name: \"positive_id\", Expr: \"(id <> 0)\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tmock: func(m mock) {\n\t\t\t\tm.ExpectQuery(sqltest.Escape(\"SELECT seq FROM sqlite_sequence WHERE name = ?\")).\n\t\t\t\t\tWithArgs(\"posts\").\n\t\t\t\t\tWillReturnError(sql.ErrNoRows)\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: \"CREATE TABLE `posts` (`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT, `text` text NULL, CHECK (text <> ''), CONSTRAINT `positive_id` CHECK (id <> 0))\", Reverse: \"DROP TABLE `posts`\"},\n\t\t\t\t\t{Cmd: `INSERT INTO sqlite_sequence (name, seq) VALUES (\"posts\", 1024)`, Reverse: `UPDATE sqlite_sequence SET seq = 0 WHERE name = \"posts\"`},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropTable{T: schema.NewTable(\"posts\").AddColumns(schema.NewIntColumn(\"id\", \"integer\"))},\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = off\"},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"DROP TABLE `posts`\",\n\t\t\t\t\t\tReverse: \"CREATE TABLE `posts` (`id` integer NOT NULL)\",\n\t\t\t\t\t},\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = on\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.DropTable{\n\t\t\t\t\tT: func() *schema.Table {\n\t\t\t\t\t\tid := schema.NewIntColumn(\"id\", \"int\")\n\t\t\t\t\t\treturn schema.NewTable(\"posts\").\n\t\t\t\t\t\t\tSetComment(\"a8m's posts\").\n\t\t\t\t\t\t\tAddColumns(id).\n\t\t\t\t\t\t\tAddIndexes(\n\t\t\t\t\t\t\t\tschema.NewIndex(\"idx\").AddColumns(id).SetComment(\"a8m's index\"),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t}(),\n\t\t\t\t},\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = off\"},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd: \"DROP TABLE `posts`\",\n\t\t\t\t\t\tReverse: []string{\n\t\t\t\t\t\t\t\"CREATE TABLE `posts` (`id` int NOT NULL)\",\n\t\t\t\t\t\t\t\"CREATE INDEX `idx` ON `posts` (`id`)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = on\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"id\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: &schema.Column{Name: \"name\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(255)\"}}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddIndex{\n\t\t\t\t\t\t\t\tI: &schema.Index{\n\t\t\t\t\t\t\t\t\tName: \"id_key\",\n\t\t\t\t\t\t\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t\t\t\t\t\t\t{C: users.Columns[0]},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t\t\t\t&schema.Comment{Text: \"comment\"},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: \"ALTER TABLE `users` ADD COLUMN `name` varchar(255) NOT NULL\", Reverse: \"ALTER TABLE `users` DROP COLUMN `name`\"},\n\t\t\t\t\t{Cmd: \"CREATE INDEX `id_key` ON `users` (`id`)\", Reverse: \"DROP INDEX `id_key`\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Add column with constant default value.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"bigint\"))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: schema.NewStringColumn(\"name\", \"text\").\n\t\t\t\t\t\t\t\t\tSetDefault(&schema.Literal{V: \"a8m\"}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: \"ALTER TABLE `users` ADD COLUMN `name` text NOT NULL DEFAULT 'a8m'\", Reverse: \"ALTER TABLE `users` DROP COLUMN `name`\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Add column with expression default value.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t\tschema.NewStringColumn(\"name\", \"text\").\n\t\t\t\t\t\t\t\tSetDefault(&schema.RawExpr{X: \"NOW()::TEXT\"}),\n\t\t\t\t\t\t)\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: users.Columns[1],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    false,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = off\"},\n\t\t\t\t\t{Cmd: \"CREATE TABLE `new_users` (`id` bigint NOT NULL, `name` text NOT NULL DEFAULT (NOW()::TEXT))\", Reverse: \"DROP TABLE `new_users`\"},\n\t\t\t\t\t{Cmd: \"INSERT INTO `new_users` (`id`) SELECT `id` FROM `users`\"},\n\t\t\t\t\t{Cmd: \"DROP TABLE `users`\"},\n\t\t\t\t\t{Cmd: \"ALTER TABLE `new_users` RENAME TO `users`\"},\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = on\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Add VIRTUAL column.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"id\", \"bigint\"))\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: schema.NewIntColumn(\"nid\", \"bigint\").\n\t\t\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\"}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: \"ALTER TABLE `users` ADD COLUMN `nid` bigint NOT NULL AS (1)\", Reverse: \"ALTER TABLE `users` DROP COLUMN `nid`\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Add STORED column.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := schema.NewTable(\"users\").\n\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"name\", \"text\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"nid\", \"bigint\").\n\t\t\t\t\t\t\t\tSetGeneratedExpr(&schema.GeneratedExpr{Expr: \"1\", Type: \"STORED\"}),\n\t\t\t\t\t\t)\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: users.Columns[2],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t// Rename should be respected in INSERT command.\n\t\t\t\t\t\t\t&schema.RenameColumn{\n\t\t\t\t\t\t\t\tFrom: schema.NewColumn(\"uname\"),\n\t\t\t\t\t\t\t\tTo:   users.Columns[1],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = off\"},\n\t\t\t\t\t{Cmd: \"CREATE TABLE `new_users` (`id` bigint NOT NULL, `name` text NOT NULL, `nid` bigint NOT NULL AS (1) STORED)\", Reverse: \"DROP TABLE `new_users`\"},\n\t\t\t\t\t{Cmd: \"INSERT INTO `new_users` (`id`, `name`) SELECT `id`, `uname` FROM `users`\"},\n\t\t\t\t\t{Cmd: \"DROP TABLE `users`\"},\n\t\t\t\t\t{Cmd: \"ALTER TABLE `new_users` RENAME TO `users`\"},\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = on\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t\tschema.NewIntColumn(\"rank\", \"int\").SetDefault(&schema.Literal{V: \"1\"}),\n\t\t\t\t\t\t\tschema.NewStringColumn(\"nick\", \"text\").SetDefault(&schema.Literal{V: \"a8m\"}),\n\t\t\t\t\t\t\tschema.NewStringColumn(\"expr\", \"text\").SetDefault(&schema.RawExpr{X: \"hex(1)\"}),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&schema.Check{Expr: \"(id <> 0)\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   schema.NewNullIntColumn(\"id\", \"bigint\"),\n\t\t\t\t\t\t\t\tTo:     users.Columns[1],\n\t\t\t\t\t\t\t\tChange: schema.ChangeNull | schema.ChangeDefault,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.ModifyColumn{\n\t\t\t\t\t\t\t\tFrom:   schema.NewNullStringColumn(\"nick\", \"text\"),\n\t\t\t\t\t\t\t\tTo:     users.Columns[2],\n\t\t\t\t\t\t\t\tChange: schema.ChangeNull | schema.ChangeDefault,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.DropColumn{\n\t\t\t\t\t\t\t\tC: &schema.Column{Name: \"name\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(255)\"}}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddCheck{\n\t\t\t\t\t\t\t\tC: &schema.Check{Expr: \"(id <> 0)\"},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = off\"},\n\t\t\t\t\t{Cmd: \"CREATE TABLE `new_users` (`id` bigint NOT NULL, `rank` int NOT NULL DEFAULT 1, `nick` text NOT NULL DEFAULT 'a8m', `expr` text NOT NULL DEFAULT (hex(1)), CHECK (id <> 0))\", Reverse: \"DROP TABLE `new_users`\"},\n\t\t\t\t\t{Cmd: \"INSERT INTO `new_users` (`id`, `rank`, `nick`, `expr`) SELECT `id`, IFNULL(`rank`, 1) AS `rank`, IFNULL(`nick`, 'a8m') AS `nick`, `expr` FROM `users`\"},\n\t\t\t\t\t{Cmd: \"DROP TABLE `users`\"},\n\t\t\t\t\t{Cmd: \"ALTER TABLE `new_users` RENAME TO `users`\"},\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = on\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Nothing to INSERT.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\tfunc() schema.Change {\n\t\t\t\t\tusers := &schema.Table{\n\t\t\t\t\t\tName: \"users\",\n\t\t\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t\t\t{Name: \"c2\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\treturn &schema.ModifyTable{\n\t\t\t\t\t\tT: users,\n\t\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t\t&schema.DropColumn{\n\t\t\t\t\t\t\t\tC: &schema.Column{Name: \"c1\", Type: &schema.ColumnType{Type: &schema.StringType{T: \"varchar(255)\"}}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddColumn{\n\t\t\t\t\t\t\t\tC: &schema.Column{Name: \"c2\", Type: &schema.ColumnType{Type: &schema.IntegerType{T: \"bigint\"}}},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t}(),\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = off\"},\n\t\t\t\t\t{Cmd: \"CREATE TABLE `new_users` (`c2` bigint NOT NULL)\", Reverse: \"DROP TABLE `new_users`\"},\n\t\t\t\t\t/* Nothing to INSERT from `users` as `c1` was dropped. */\n\t\t\t\t\t{Cmd: \"DROP TABLE `users`\"},\n\t\t\t\t\t{Cmd: \"ALTER TABLE `new_users` RENAME TO `users`\"},\n\t\t\t\t\t{Cmd: \"PRAGMA foreign_keys = on\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.RenameTable{\n\t\t\t\t\tFrom: schema.NewTable(\"t1\"),\n\t\t\t\t\tTo:   schema.NewTable(\"t2\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `t1` RENAME TO `t2`\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `t2` RENAME TO `t1`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"t1\"),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameColumn{\n\t\t\t\t\t\t\tFrom: schema.NewColumn(\"a\"),\n\t\t\t\t\t\t\tTo:   schema.NewColumn(\"b\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"ALTER TABLE `t1` RENAME COLUMN `a` TO `b`\",\n\t\t\t\t\t\tReverse: \"ALTER TABLE `t1` RENAME COLUMN `b` TO `a`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\tT: schema.NewTable(\"t1\"),\n\t\t\t\t\tChanges: []schema.Change{\n\t\t\t\t\t\t&schema.RenameIndex{\n\t\t\t\t\t\t\tFrom: schema.NewIndex(\"a\").AddColumns(schema.NewColumn(\"a\")),\n\t\t\t\t\t\t\tTo:   schema.NewIndex(\"b\").AddColumns(schema.NewColumn(\"a\")),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"CREATE INDEX `b` ON `t1` (`a`)\",\n\t\t\t\t\t\tReverse: \"DROP INDEX `b`\",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"DROP INDEX `a`\",\n\t\t\t\t\t\tReverse: \"CREATE INDEX `a` ON `t1` (`a`)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// The default is no qualifier.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{T: schema.NewTable(\"t\").SetSchema(schema.New(\"main\")).AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"CREATE TABLE `t` (`a` int NOT NULL)\",\n\t\t\t\t\t\tReverse: \"DROP TABLE `t`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t// Custom qualifier.\n\t\t{\n\t\t\tchanges: []schema.Change{\n\t\t\t\t&schema.AddTable{T: schema.NewTable(\"t\").SetSchema(schema.New(\"d\")).AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t\t\t},\n\t\t\toptions: []migrate.PlanOption{\n\t\t\t\tfunc(o *migrate.PlanOptions) {\n\t\t\t\t\ts := \"other\"\n\t\t\t\t\to.SchemaQualifier = &s\n\t\t\t\t},\n\t\t\t},\n\t\t\tplan: &migrate.Plan{\n\t\t\t\tReversible:    true,\n\t\t\t\tTransactional: true,\n\t\t\t\tChanges: []*migrate.Change{\n\t\t\t\t\t{\n\t\t\t\t\t\tCmd:     \"CREATE TABLE `other`.`t` (`a` int NOT NULL)\",\n\t\t\t\t\t\tReverse: \"DROP TABLE `other`.`t`\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tdb, mk, err := sqlmock.New()\n\t\t\trequire.NoError(t, err)\n\t\t\tm := mock{mk}\n\t\t\tif tt.mock != nil {\n\t\t\t\ttt.mock(m)\n\t\t\t}\n\t\t\tdrv, err := Open(db)\n\t\t\trequire.NoError(t, err)\n\t\t\tplan, err := drv.PlanChanges(context.Background(), \"plan\", tt.changes, tt.options...)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.plan.Reversible, plan.Reversible)\n\t\t\trequire.Equal(t, tt.plan.Transactional, plan.Transactional)\n\t\t\tfor i, c := range plan.Changes {\n\t\t\t\trequire.Equal(t, tt.plan.Changes[i].Cmd, c.Cmd)\n\t\t\t\trequire.Equal(t, tt.plan.Changes[i].Reverse, c.Reverse)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestDefaultPlan(t *testing.T) {\n\tchanges, err := DefaultPlan.PlanChanges(context.Background(), \"plan\", []schema.Change{\n\t\t&schema.AddTable{T: schema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, 1, len(changes.Changes))\n\trequire.Equal(t, \"CREATE TABLE `t1` (`a` int NOT NULL)\", changes.Changes[0].Cmd)\n\n\terr = DefaultPlan.ApplyChanges(context.Background(), []schema.Change{\n\t\t&schema.AddTable{T: schema.NewTable(\"t1\").AddColumns(schema.NewIntColumn(\"a\", \"int\"))},\n\t})\n\trequire.EqualError(t, err, `create \"t1\" table: cannot execute statements without a database connection. use Open to create a new Driver`)\n}\n\nfunc TestIndentedPlan(t *testing.T) {\n\ttests := []struct {\n\t\tT   *schema.Table\n\t\tCmd string\n\t}{\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tSetPrimaryKey(\n\t\t\t\t\tschema.NewPrimaryKey(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\t),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL,\",\n\t\t\t\t\"  `id` int NOT NULL,\",\n\t\t\t\t\"  PRIMARY KEY (`id`)\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tAddForeignKeys(\n\t\t\t\t\tschema.NewForeignKey(\"fk1\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t\tschema.NewForeignKey(\"fk2\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL,\",\n\t\t\t\t\"  CONSTRAINT `fk1` FOREIGN KEY (`a`) REFERENCES `t2` (`a`),\",\n\t\t\t\t\"  CONSTRAINT `fk2` FOREIGN KEY (`a`) REFERENCES `t2` (`a`)\",\n\t\t\t\t\")\",\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tT: schema.NewTable(\"t1\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"a\", \"int\"),\n\t\t\t\t\tschema.NewIntColumn(\"b\", \"int\"),\n\t\t\t\t).\n\t\t\t\tSetPrimaryKey(\n\t\t\t\t\tschema.NewPrimaryKey(schema.NewIntColumn(\"id\", \"int\")),\n\t\t\t\t).\n\t\t\t\tAddForeignKeys(\n\t\t\t\t\tschema.NewForeignKey(\"fk1\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t\tschema.NewForeignKey(\"fk2\").\n\t\t\t\t\t\tAddColumns(schema.NewIntColumn(\"a\", \"int\")).\n\t\t\t\t\t\tSetRefTable(schema.NewTable(\"t2\")).\n\t\t\t\t\t\tAddRefColumns(schema.NewIntColumn(\"a\", \"int\")),\n\t\t\t\t).\n\t\t\t\tAddChecks(\n\t\t\t\t\tschema.NewCheck().SetName(\"ck1\").SetExpr(\"a > 0\"),\n\t\t\t\t\tschema.NewCheck().SetName(\"ck2\").SetExpr(\"a > 0\"),\n\t\t\t\t),\n\t\t\tCmd: join(\n\t\t\t\t\"CREATE TABLE `t1` (\",\n\t\t\t\t\"  `a` int NOT NULL,\",\n\t\t\t\t\"  `b` int NOT NULL,\",\n\t\t\t\t\"  `id` int NOT NULL,\",\n\t\t\t\t\"  PRIMARY KEY (`id`),\",\n\t\t\t\t\"  CONSTRAINT `fk1` FOREIGN KEY (`a`) REFERENCES `t2` (`a`),\",\n\t\t\t\t\"  CONSTRAINT `fk2` FOREIGN KEY (`a`) REFERENCES `t2` (`a`),\",\n\t\t\t\t\"  CONSTRAINT `ck1` CHECK (a > 0),\",\n\t\t\t\t\"  CONSTRAINT `ck2` CHECK (a > 0)\",\n\t\t\t\t`)`,\n\t\t\t),\n\t\t},\n\t}\n\tfor i, tt := range tests {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tdb, _, err := sqlmock.New()\n\t\t\trequire.NoError(t, err)\n\t\t\tdrv, err := Open(db)\n\t\t\trequire.NoError(t, err)\n\t\t\tplan, err := drv.PlanChanges(context.Background(), \"wantPlan\", []schema.Change{&schema.AddTable{T: tt.T}}, func(opts *migrate.PlanOptions) {\n\t\t\t\topts.Indent = \"  \"\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, plan.Changes, 1)\n\t\t\trequire.Equal(t, tt.Cmd, plan.Changes[0].Cmd)\n\t\t})\n\t}\n}\n\nfunc join(lines ...string) string { return strings.Join(lines, \"\\n\") }\n"
  },
  {
    "path": "sql/sqlite/sqlitecheck/sqlitecheck.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlitecheck\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlcheck/condrop\"\n\t\"ariga.io/atlas/sql/sqlcheck/datadepend\"\n\t\"ariga.io/atlas/sql/sqlcheck/destructive\"\n\t\"ariga.io/atlas/sql/sqlcheck/incompatible\"\n\t\"ariga.io/atlas/sql/sqlite\"\n)\n\n// codeModNotNullC is an SQLite specific code for reporting modifying nullable columns to non-nullable.\nvar codeModNotNullC = sqlcheck.Code(\"LT101\")\n\nfunc addNotNull(p *datadepend.ColumnPass) (diags []sqlcheck.Diagnostic, err error) {\n\ttt, err := sqlite.FormatType(p.Column.Type.Type)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []sqlcheck.Diagnostic{\n\t\t{\n\t\t\tPos: p.Change.Stmt.Pos,\n\t\t\tText: fmt.Sprintf(\n\t\t\t\t\"Adding a non-nullable %q column %q will fail in case table %q is not empty\",\n\t\t\t\ttt, p.Column.Name, p.Table.Name,\n\t\t\t),\n\t\t},\n\t}, nil\n}\n\nfunc modifyNotNull(p *datadepend.ColumnPass) (diags []sqlcheck.Diagnostic, err error) {\n\tif p.Column.Default != nil || datadepend.ColumnFilled(p.Pass, p.Table, p.Column, p.Change.Stmt.Pos) {\n\t\treturn nil, nil\n\t}\n\treturn []sqlcheck.Diagnostic{\n\t\t{\n\t\t\tPos:  p.Change.Stmt.Pos,\n\t\t\tCode: codeModNotNullC,\n\t\t\tText: fmt.Sprintf(\"Modifying nullable column %q to non-nullable without default value might fail in case it contains NULL values\", p.Column.Name),\n\t\t},\n\t}, nil\n}\n\nfunc analyzers(r *schemahcl.Resource) ([]sqlcheck.Analyzer, error) {\n\tds, err := destructive.New(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcd, err := condrop.New(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdd, err := datadepend.New(r, datadepend.Handler{\n\t\tAddNotNull:    addNotNull,\n\t\tModifyNotNull: modifyNotNull,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbc, err := incompatible.New(r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []sqlcheck.Analyzer{\n\t\tsqlcheck.AnalyzerFunc(func(_ context.Context, p *sqlcheck.Pass) error {\n\t\t\tvar changes []*sqlcheck.Change\n\t\t\t// Detect sequence of changes using temporary table and transform them to one ModifyTable change.\n\t\t\t// See: https://www.sqlite.org/lang_altertable.html#making_other_kinds_of_table_schema_changes.\n\t\t\tfor i := 0; i < len(p.File.Changes); i++ {\n\t\t\t\tif i+3 >= len(p.File.Changes) {\n\t\t\t\t\tchanges = append(changes, p.File.Changes[i])\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tprevT, currT, ok := modifyUsingTemp(p.File.Changes[i], p.File.Changes[i+2], p.File.Changes[i+3])\n\t\t\t\tif !ok {\n\t\t\t\t\tchanges = append(changes, p.File.Changes[i])\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tdiff, err := p.Dev.Driver.TableDiff(prevT, currT)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tchanges = append(changes, &sqlcheck.Change{\n\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t// Use the position of the first statement.\n\t\t\t\t\t\tPos: p.File.Changes[i].Stmt.Pos,\n\t\t\t\t\t\t// A combined statement.\n\t\t\t\t\t\tText: strings.Join([]string{\n\t\t\t\t\t\t\tp.File.Changes[i].Stmt.Text,\n\t\t\t\t\t\t\tp.File.Changes[i+2].Stmt.Text,\n\t\t\t\t\t\t\tp.File.Changes[i+3].Stmt.Text,\n\t\t\t\t\t\t}, \"\\n\"),\n\t\t\t\t\t},\n\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t&schema.ModifyTable{\n\t\t\t\t\t\t\tT:       currT,\n\t\t\t\t\t\t\tChanges: diff,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\ti += 3\n\t\t\t}\n\t\t\tp.File.Changes = changes\n\t\t\treturn nil\n\t\t}),\n\t\tds, dd, cd, bc,\n\t}, nil\n}\n\n// modifyUsingTemp indicates if the 3 changes represents a table modification using\n// the pattern mentioned in the link below: \"CREATE\", \"INSERT\", \"DROP\" and \"RENAME\".\nfunc modifyUsingTemp(c1, c2, c3 *sqlcheck.Change) (from, to *schema.Table, _ bool) {\n\tif len(c1.Changes) != 1 || !isAddT(c1.Changes[0], \"new_\") || len(c2.Changes) != 1 || len(c3.Changes) == 0 {\n\t\treturn nil, nil, false\n\t}\n\t// New table layout.\n\tadd := c1.Changes[0].(*schema.AddTable)\n\tprefixed, name := add.T.Name, strings.TrimPrefix(add.T.Name, \"new_\")\n\tadd.T.Name = name\n\t// Right after \"INSERT\", the \"DROP T\" is expected.\n\tif !isDropT(c2.Changes[0], name) {\n\t\treturn nil, nil, false\n\t}\n\tdrop := c2.Changes[0].(*schema.DropTable)\n\t// \"RENAME T\" is expected after \"DROP T\".\n\tif len(c3.Changes) == 1 && isRenameT(c3.Changes[0], prefixed, name) {\n\t\treturn drop.T, add.T, true\n\t}\n\t// In case no parser is attached, \"RENAME T\" will be presented as \"DROP T\" and \"ADD T\".\n\tif len(c3.Changes) == 2 && isDropT(c3.Changes[0], prefixed) && isAddT(c3.Changes[1], name) {\n\t\treturn drop.T, add.T, true\n\t}\n\treturn nil, nil, false\n}\n\nfunc isAddT(c schema.Change, prefix string) bool {\n\ta, ok := c.(*schema.AddTable)\n\treturn ok && strings.HasPrefix(a.T.Name, prefix)\n}\n\nfunc isDropT(c schema.Change, name string) bool {\n\td, ok := c.(*schema.DropTable)\n\treturn ok && d.T.Name == name\n}\n\nfunc isRenameT(c schema.Change, from, to string) bool {\n\tr, ok := c.(*schema.RenameTable)\n\treturn ok && r.From.Name == from && r.To.Name == to\n}\n"
  },
  {
    "path": "sql/sqlite/sqlitecheck/sqlitecheck_oss.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !ent\n\npackage sqlitecheck\n\nimport (\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlite\"\n)\n\nfunc init() {\n\tsqlcheck.Register(sqlite.DriverName, analyzers)\n}\n"
  },
  {
    "path": "sql/sqlite/sqlitecheck/sqlitecheck_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlitecheck_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlcheck\"\n\t\"ariga.io/atlas/sql/sqlclient\"\n\t\"ariga.io/atlas/sql/sqlite\"\n\t_ \"ariga.io/atlas/sql/sqlite/sqlitecheck\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDetectModifyTable(t *testing.T) {\n\tvar (\n\t\treport *sqlcheck.Report\n\t\tpass   = &sqlcheck.Pass{\n\t\t\tDev: &sqlclient.Client{\n\t\t\t\tDriver: func() migrate.Driver {\n\t\t\t\t\tdrv := &sqlite.Driver{}\n\t\t\t\t\tdrv.Differ = sqlite.DefaultDiff\n\t\t\t\t\treturn drv\n\t\t\t\t}(),\n\t\t\t},\n\t\t\tFile: &sqlcheck.File{\n\t\t\t\tFile: testFile{name: \"1.sql\"},\n\t\t\t\tChanges: []*sqlcheck.Change{\n\t\t\t\t\t// A real drop.\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"DROP TABLE `users`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.DropTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"users\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"main\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t// Table modification using a temporary table.\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"PRAGMA foreign_keys = off;\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"CREATE TABLE `new_posts` (`text` text NOT NULL);\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.AddTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"new_posts\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"main\")).\n\t\t\t\t\t\t\t\t\tAddColumns(schema.NewStringColumn(\"text\", \"text\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"INSERT INTO `new_posts` (`text`) SELECT `text` FROM `posts`;\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"DROP TABLE `posts`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.DropTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"main\")).\n\t\t\t\t\t\t\t\t\tAddColumns(\n\t\t\t\t\t\t\t\t\t\tschema.NewNullStringColumn(\"text\", \"text\"),\n\t\t\t\t\t\t\t\t\t\tschema.NewTimeColumn(\"posted_at\", \"timestamp\"),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"ALTER TABLE `new_posts` RENAME TO `posts`;\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.DropTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"new_posts\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"main\")).\n\t\t\t\t\t\t\t\t\tAddColumns(schema.NewStringColumn(\"text\", \"text\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t&schema.AddTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"posts\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"main\")).\n\t\t\t\t\t\t\t\t\tAddColumns(schema.NewStringColumn(\"text\", \"text\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"PRAGMA foreign_keys = on;\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t// Another real drop.\n\t\t\t\t\t{\n\t\t\t\t\t\tStmt: &migrate.Stmt{\n\t\t\t\t\t\t\tText: \"DROP TABLE `pets`\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tChanges: schema.Changes{\n\t\t\t\t\t\t\t&schema.DropTable{\n\t\t\t\t\t\t\t\tT: schema.NewTable(\"pets\").\n\t\t\t\t\t\t\t\t\tSetSchema(schema.New(\"main\")),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tReporter: sqlcheck.ReportWriterFunc(func(r sqlcheck.Report) {\n\t\t\t\treport = &r\n\t\t\t}),\n\t\t}\n\t)\n\tazs, err := sqlcheck.AnalyzerFor(sqlite.DriverName, nil)\n\trequire.NoError(t, err)\n\trequire.NoError(t, azs[0].Analyze(context.Background(), pass))\n\terr = azs[1].Analyze(context.Background(), pass)\n\trequire.EqualError(t, err, \"destructive changes detected\")\n\n\trequire.Equal(t, report.Text, \"destructive changes detected\")\n\trequire.Len(t, report.Diagnostics, 3)\n\trequire.Equal(t, report.Diagnostics[0].Text, `Dropping table \"users\"`)\n\trequire.Equal(t, report.Diagnostics[1].Text, `Dropping non-virtual column \"posted_at\"`)\n\trequire.Equal(t, report.Diagnostics[2].Text, `Dropping table \"pets\"`)\n\n\trequire.NoError(t, azs[2].Analyze(context.Background(), pass))\n\trequire.Equal(t, report.Text, \"data dependent changes detected\")\n\trequire.Len(t, report.Diagnostics, 1)\n\trequire.Equal(t, report.Diagnostics[0].Text, `Modifying nullable column \"text\" to non-nullable without default value might fail in case it contains NULL values`)\n}\n\ntype testFile struct {\n\tname string\n\tmigrate.File\n}\n\nfunc (t testFile) Name() string {\n\treturn t.name\n}\n"
  },
  {
    "path": "sql/sqlite/sqlspec.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\t\"ariga.io/atlas/sql/internal/specutil\"\n\t\"ariga.io/atlas/sql/internal/sqlx\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"ariga.io/atlas/sql/sqlspec\"\n\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\ntype doc struct {\n\tTables   []*sqlspec.Table   `spec:\"table\"`\n\tViews    []*sqlspec.View    `spec:\"view\"`\n\tTriggers []*sqlspec.Trigger `spec:\"trigger\"`\n\tSchemas  []*sqlspec.Schema  `spec:\"schema\"`\n}\n\n// Codec for schemahcl.\ntype Codec struct {\n\tState *schemahcl.State\n}\n\n// Eval evaluates an Atlas DDL document into v using the input.\nfunc (c *Codec) Eval(p *hclparse.Parser, v any, input map[string]cty.Value) error {\n\treturn c.EvalOptions(p, v, &schemahcl.EvalOptions{Variables: input})\n}\n\n// EvalOptions decodes the HCL with the given options.\nfunc (c *Codec) EvalOptions(p *hclparse.Parser, v any, opts *schemahcl.EvalOptions) error {\n\tswitch v := v.(type) {\n\tcase *schema.Realm:\n\t\tvar d doc\n\t\tif err := c.State.EvalOptions(p, &d, opts); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := specutil.Scan(v,\n\t\t\t&specutil.ScanDoc{Schemas: d.Schemas, Tables: d.Tables, Views: d.Views, Triggers: d.Triggers},\n\t\t\tscanFuncs,\n\t\t); err != nil {\n\t\t\treturn fmt.Errorf(\"sqlite: failed converting to *schema.Realm: %w\", err)\n\t\t}\n\tcase *schema.Schema:\n\t\tvar d doc\n\t\tif err := c.State.EvalOptions(p, &d, opts); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(d.Schemas) != 1 {\n\t\t\treturn fmt.Errorf(\"sqlite: expecting document to contain a single schema, got %d\", len(d.Schemas))\n\t\t}\n\t\tr := &schema.Realm{}\n\t\tif err := specutil.Scan(r,\n\t\t\t&specutil.ScanDoc{Schemas: d.Schemas, Tables: d.Tables, Views: d.Views, Triggers: d.Triggers},\n\t\t\tscanFuncs,\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t*v = *r.Schemas[0]\n\tcase schema.Schema, schema.Realm:\n\t\treturn fmt.Errorf(\"sqlite: Eval expects a pointer: received %[1]T, expected *%[1]T\", v)\n\tdefault:\n\t\treturn fmt.Errorf(\"sqlite: unexpected type %T\", v)\n\t}\n\treturn nil\n}\n\n// MarshalSpec marshals v into an Atlas DDL document using a schemahcl.Marshaler.\nfunc (c *Codec) MarshalSpec(v any) ([]byte, error) {\n\treturn specutil.Marshal(v, c.State, specutil.RealmFuncs{\n\t\tSchema:   schemaSpec,\n\t\tTriggers: triggersSpec,\n\t})\n}\n\n// convertTable converts a sqlspec.Table to a schema.Table. Table conversion is done without converting\n// ForeignKeySpecs into ForeignKeys, as the target tables do not necessarily exist in the schema\n// at this point. Instead, the linking is done by the convertSchema function.\nfunc convertTable(spec *sqlspec.Table, parent *schema.Schema) (*schema.Table, error) {\n\tt, err := specutil.Table(spec, parent, convertColumn, specutil.PrimaryKey, convertIndex, specutil.Check)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif attr, ok := spec.Attr(\"without_rowid\"); ok {\n\t\tb, err := attr.Bool()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif b {\n\t\t\tt.AddAttrs(&WithoutRowID{})\n\t\t}\n\t}\n\tif attr, ok := spec.Attr(\"strict\"); ok {\n\t\tb, err := attr.Bool()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif b {\n\t\t\tt.AddAttrs(&Strict{})\n\t\t}\n\t}\n\treturn t, nil\n}\n\n// convertView converts a sqlspec.View to a schema.View.\nfunc convertView(spec *sqlspec.View, parent *schema.Schema) (*schema.View, error) {\n\tv, err := specutil.View(\n\t\tspec, parent,\n\t\tfunc(c *sqlspec.Column, _ *schema.View) (*schema.Column, error) {\n\t\t\treturn specutil.Column(c, convertColumnType)\n\t\t},\n\t\tfunc(i *sqlspec.Index, v *schema.View) (*schema.Index, error) {\n\t\t\treturn nil, fmt.Errorf(\"unexpected view index %s.%s\", v.Name, i.Name)\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn v, nil\n}\n\n// convertIndex converts a sqlspec.Index into a schema.Index.\nfunc convertIndex(spec *sqlspec.Index, t *schema.Table) (*schema.Index, error) {\n\tidx, err := specutil.Index(spec, t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif attr, ok := spec.Attr(\"where\"); ok {\n\t\tp, err := attr.String()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tidx.Attrs = append(idx.Attrs, &IndexPredicate{P: p})\n\t}\n\treturn idx, nil\n}\n\n// convertColumn converts a sqlspec.Column into a schema.Column.\nfunc convertColumn(spec *sqlspec.Column, _ *schema.Table) (*schema.Column, error) {\n\tc, err := specutil.Column(spec, convertColumnType)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif attr, ok := spec.Attr(\"auto_increment\"); ok {\n\t\tb, err := attr.Bool()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif b {\n\t\t\tc.AddAttrs(&AutoIncrement{})\n\t\t}\n\t}\n\tif err := specutil.ConvertGenExpr(spec.Remain(), c, storedOrVirtual); err != nil {\n\t\treturn nil, err\n\t}\n\treturn c, nil\n}\n\n// convertColumnType converts a sqlspec.Column into a concrete SQLite schema.Type.\nfunc convertColumnType(spec *sqlspec.Column) (schema.Type, error) {\n\treturn TypeRegistry.Type(spec.Type, spec.Extra.Attrs)\n}\n\n// schemaSpec converts from a concrete SQLite schema to Atlas specification.\nfunc schemaSpec(s *schema.Schema) (*specutil.SchemaSpec, error) {\n\treturn specutil.FromSchema(s, &specutil.SchemaFuncs{\n\t\tTable: tableSpec,\n\t\tView:  viewSpec,\n\t})\n}\n\n// tableSpec converts from a concrete SQLite sqlspec.Table to a schema.Table.\nfunc tableSpec(t *schema.Table) (*sqlspec.Table, error) {\n\tspec, err := specutil.FromTable(\n\t\tt,\n\t\tcolumnSpec,\n\t\tspecutil.FromPrimaryKey,\n\t\tindexSpec,\n\t\tspecutil.FromForeignKey,\n\t\tspecutil.FromCheck,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\toptions := &schemahcl.Resource{}\n\tif sqlx.Has(t.Attrs, &WithoutRowID{}) {\n\t\toptions.SetAttr(schemahcl.BoolAttr(\"without_rowid\", true))\n\t}\n\tif sqlx.Has(t.Attrs, &Strict{}) {\n\t\toptions.SetAttr(schemahcl.BoolAttr(\"strict\", true))\n\t}\n\tif options != nil {\n\t\tspec.Extra.Children = append(spec.Extra.Children, options)\n\t}\n\treturn spec, nil\n}\n\n// viewSpec converts from a concrete SQLite schema.View to a sqlspec.View.\nfunc viewSpec(view *schema.View) (*sqlspec.View, error) {\n\tspec, err := specutil.FromView(\n\t\tview,\n\t\tfunc(c *schema.Column, _ *schema.View) (*sqlspec.Column, error) {\n\t\t\treturn specutil.FromColumn(c, columnTypeSpec)\n\t\t},\n\t\tindexSpec,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn spec, nil\n}\n\nfunc indexSpec(idx *schema.Index) (*sqlspec.Index, error) {\n\tspec, err := specutil.FromIndex(idx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif i := (IndexPredicate{}); sqlx.Has(idx.Attrs, &i) && i.P != \"\" {\n\t\tspec.Extra.Attrs = append(spec.Extra.Attrs, specutil.VarAttr(\"where\", strconv.Quote(i.P)))\n\t}\n\treturn spec, nil\n}\n\n// columnSpec converts from a concrete SQLite schema.Column into a sqlspec.Column.\nfunc columnSpec(c *schema.Column, _ *schema.Table) (*sqlspec.Column, error) {\n\ts, err := specutil.FromColumn(c, columnTypeSpec)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif sqlx.Has(c.Attrs, &AutoIncrement{}) {\n\t\ts.Extra.Attrs = append(s.Extra.Attrs, schemahcl.BoolAttr(\"auto_increment\", true))\n\t}\n\tif x := (schema.GeneratedExpr{}); sqlx.Has(c.Attrs, &x) {\n\t\ts.Extra.Children = append(s.Extra.Children, specutil.FromGenExpr(x, storedOrVirtual))\n\t}\n\treturn s, nil\n}\n\n// columnTypeSpec converts from a concrete MySQL schema.Type into sqlspec.Column Type.\nfunc columnTypeSpec(t schema.Type) (*sqlspec.Column, error) {\n\tst, err := TypeRegistry.Convert(t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &sqlspec.Column{Type: st}, nil\n}\n\n// TypeRegistry contains the supported TypeSpecs for the sqlite driver.\nvar TypeRegistry = schemahcl.NewRegistry(\n\tschemahcl.WithFormatter(FormatType),\n\tschemahcl.WithParser(ParseType),\n\tschemahcl.WithSpecs(\n\t\tschemahcl.NewTypeSpec(TypeReal, schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr(), schemahcl.ScaleTypeAttr())),\n\t\tschemahcl.NewTypeSpec(TypeBlob, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeText, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(TypeInteger, schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"int\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"tinyint\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"smallint\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"mediumint\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"bigint\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.AliasTypeSpec(\"unsigned_big_int\", \"unsigned big int\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"int2\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"int8\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"uint64\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"double\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.AliasTypeSpec(\"double_precision\", \"double precision\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"float\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"character\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"varchar\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.AliasTypeSpec(\"varying_character\", \"varying character\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"nchar\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.AliasTypeSpec(\"native_character\", \"native character\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"nvarchar\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"clob\", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),\n\t\tschemahcl.NewTypeSpec(\"numeric\", schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr(), schemahcl.ScaleTypeAttr())),\n\t\tschemahcl.NewTypeSpec(\"decimal\", schemahcl.WithAttributes(schemahcl.PrecisionTypeAttr(), schemahcl.ScaleTypeAttr())),\n\t\tschemahcl.NewTypeSpec(\"bool\"),\n\t\tschemahcl.NewTypeSpec(\"boolean\"),\n\t\tschemahcl.NewTypeSpec(\"date\"),\n\t\tschemahcl.NewTypeSpec(\"datetime\"),\n\t\tschemahcl.NewTypeSpec(\"json\"),\n\t\tschemahcl.NewTypeSpec(\"uuid\"),\n\t\tschemahcl.NewTypeSpec(\"jsonb\"),\n\t),\n)\n\nvar (\n\tcodec = &Codec{\n\t\tState: schemahcl.New(append(\n\t\t\tspecOptions,\n\t\t\tschemahcl.WithTypes(\"table.column.type\", TypeRegistry.Specs()),\n\t\t\tschemahcl.WithTypes(\"view.column.type\", TypeRegistry.Specs()),\n\t\t\tschemahcl.WithScopedEnums(\"table.column.as.type\", stored, virtual),\n\t\t\tschemahcl.WithScopedEnums(\"table.foreign_key.on_update\", specutil.ReferenceVars...),\n\t\t\tschemahcl.WithScopedEnums(\"table.foreign_key.on_delete\", specutil.ReferenceVars...),\n\t\t)...),\n\t}\n\t// MarshalHCL marshals v into an Atlas HCL DDL document.\n\tMarshalHCL = schemahcl.MarshalerFunc(codec.MarshalSpec)\n\t// EvalHCL implements the schemahcl.Evaluator interface.\n\tEvalHCL = schemahcl.EvalFunc(codec.Eval)\n\t// EvalHCLBytes is a helper that evaluates an HCL document from a byte slice instead\n\t// of from an hclparse.Parser instance.\n\tEvalHCLBytes = specutil.HCLBytesFunc(EvalHCL)\n)\n\n// storedOrVirtual returns a STORED or VIRTUAL\n// generated type option based on the given string.\nfunc storedOrVirtual(s string) string {\n\tif s = strings.ToUpper(s); s == \"\" {\n\t\treturn virtual\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "sql/sqlite/sqlspec_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlite\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"ariga.io/atlas/sql/internal/spectest\"\n\t\"ariga.io/atlas/sql/schema\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSQLSpec(t *testing.T) {\n\tf := `\nschema \"schema\" {\n}\n\ntable \"table\" {\n\tschema = schema.schema\n\tcolumn \"id\" {\n\t\ttype = integer\n\t\tauto_increment = true\n\t}\n\tcolumn \"age\" {\n\t\ttype = integer\n\t}\n\tcolumn \"price\" {\n\t\ttype = integer\n\t}\n\tcolumn \"account_name\" {\n\t\ttype = varchar(32)\n\t}\n\tprimary_key {\n\t\tcolumns = [table.table.column.id]\n\t}\n\tindex \"index\" {\n\t\tunique = true\n\t\tcolumns = [\n\t\t\ttable.table.column.id,\n\t\t\ttable.table.column.age,\n\t\t]\n\t\twhere = \"age <> 0\"\n\t}\n\tforeign_key \"accounts\" {\n\t\tcolumns = [\n\t\t\ttable.table.column.account_name,\n\t\t]\n\t\tref_columns = [\n\t\t\ttable.accounts.column.name,\n\t\t]\n\t\ton_delete = SET_NULL\n\t}\n\tcheck \"positive price\" {\n\t\texpr = \"price > 0\"\n\t}\n\twithout_rowid = true\n\tstrict        = false\n}\n\ntable \"accounts\" {\n\tschema = schema.schema\n\tcolumn \"name\" {\n\t\ttype = varchar(32)\n\t}\n\tprimary_key {\n\t\tcolumns = [table.accounts.column.name]\n\t}\n\tstrict = true\n}\n`\n\texp := schema.NewRealm(schema.New(\"schema\")).Schemas[0]\n\texp.Tables = []*schema.Table{\n\t\t{\n\t\t\tName:   \"table\",\n\t\t\tSchema: exp,\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{\n\t\t\t\t\tName: \"id\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\t\tT: \"integer\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t&AutoIncrement{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"age\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\t\tT: \"integer\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"price\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.IntegerType{\n\t\t\t\t\t\t\tT: \"integer\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName: \"account_name\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.StringType{\n\t\t\t\t\t\t\tT:    \"varchar\",\n\t\t\t\t\t\t\tSize: 32,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&schema.Check{\n\t\t\t\t\tName: \"positive price\",\n\t\t\t\t\tExpr: \"price > 0\",\n\t\t\t\t},\n\t\t\t\t&WithoutRowID{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName:   \"accounts\",\n\t\t\tSchema: exp,\n\t\t\tColumns: []*schema.Column{\n\t\t\t\t{\n\t\t\t\t\tName: \"name\",\n\t\t\t\t\tType: &schema.ColumnType{\n\t\t\t\t\t\tType: &schema.StringType{\n\t\t\t\t\t\t\tT:    \"varchar\",\n\t\t\t\t\t\t\tSize: 32,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&Strict{},\n\t\t\t},\n\t\t},\n\t}\n\texp.Tables[0].PrimaryKey = &schema.Index{\n\t\tTable: exp.Tables[0],\n\t\tParts: []*schema.IndexPart{\n\t\t\t{SeqNo: 0, C: exp.Tables[0].Columns[0]},\n\t\t},\n\t}\n\texp.Tables[0].Indexes = []*schema.Index{\n\t\t{\n\t\t\tName:   \"index\",\n\t\t\tTable:  exp.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: exp.Tables[0].Columns[0]},\n\t\t\t\t{SeqNo: 1, C: exp.Tables[0].Columns[1]},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexPredicate{P: \"age <> 0\"},\n\t\t\t},\n\t\t},\n\t}\n\texp.Tables[0].ForeignKeys = []*schema.ForeignKey{\n\t\t{\n\t\t\tSymbol:     \"accounts\",\n\t\t\tTable:      exp.Tables[0],\n\t\t\tColumns:    []*schema.Column{exp.Tables[0].Columns[3]},\n\t\t\tRefTable:   exp.Tables[1],\n\t\t\tRefColumns: []*schema.Column{exp.Tables[1].Columns[0]},\n\t\t\tOnDelete:   schema.SetNull,\n\t\t},\n\t}\n\texp.Tables[1].PrimaryKey = &schema.Index{\n\t\tTable: exp.Tables[1],\n\t\tParts: []*schema.IndexPart{\n\t\t\t{SeqNo: 0, C: exp.Tables[1].Columns[0]},\n\t\t},\n\t}\n\texp.Tables[0].Columns[0].AddIndexes(exp.Tables[0].PrimaryKey)\n\texp.Tables[0].Columns[0].AddIndexes(exp.Tables[0].Indexes[0])\n\texp.Tables[0].Columns[1].AddIndexes(exp.Tables[0].Indexes[0])\n\texp.Tables[1].Columns[0].AddIndexes(exp.Tables[1].PrimaryKey)\n\tvar s schema.Schema\n\terr := EvalHCLBytes([]byte(f), &s, nil)\n\trequire.NoError(t, err)\n\trequire.EqualValues(t, exp, &s)\n}\n\nfunc TestUnmarshalViews(t *testing.T) {\n\tf := `table \"t1\" {\n  schema = schema.public\n  column \"id\" {\n    null = false\n    type = int\n  }\n}\nview \"v1\" {\n schema = schema.public\n as     = \"SELECT * FROM t2 WHERE id IS NOT NULL\"\n}\nview \"v2\" {\n  schema = schema.public\n  column \"id\" {\n    null = false\n    type = int\n  }\n  as      = \"SELECT * FROM t3 WHERE id IS NOT NULL ORDER BY id\"\n  comment = \"view comment\"\n}\nview \"v3\" {\n  schema     = schema.public\n  as         = \"SELECT * FROM v2 JOIN t1 USING (id)\"\n  depends_on = [view.v1, table.t1]\n}\nschema \"public\" {\n}\n`\n\tvar (\n\t\tr   schema.Realm\n\t\ts   schema.Schema\n\t\texp = schema.New(\"public\").\n\t\t\tAddTables(\n\t\t\t\tschema.NewTable(\"t1\").\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t),\n\t\t\t).\n\t\t\tAddViews(\n\t\t\t\tschema.NewView(\"v1\", \"SELECT * FROM t2 WHERE id IS NOT NULL\"),\n\t\t\t\tschema.NewView(\"v2\", \"SELECT * FROM t3 WHERE id IS NOT NULL ORDER BY id\").\n\t\t\t\t\tAddColumns(\n\t\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t\t).\n\t\t\t\t\tSetComment(\"view comment\"),\n\t\t\t)\n\t)\n\texp.AddViews(\n\t\tschema.NewView(\"v3\", \"SELECT * FROM v2 JOIN t1 USING (id)\").\n\t\t\tAddDeps(exp.Views[0], exp.Tables[0]),\n\t)\n\tr.AddSchemas(exp)\n\trequire.NoError(t, EvalHCLBytes([]byte(f), &s, nil))\n\trequire.EqualValues(t, exp, &s)\n}\n\nfunc TestMarshalSpec_AutoIncrement(t *testing.T) {\n\ts := &schema.Schema{\n\t\tName: \"test\",\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"id\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&AutoIncrement{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\ts.Tables[0].Schema = s\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"id\" {\n    null           = false\n    type           = int\n    auto_increment = true\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestMarshalSpec_IndexPredicate(t *testing.T) {\n\ts := &schema.Schema{\n\t\tName: \"test\",\n\t\tTables: []*schema.Table{\n\t\t\t{\n\t\t\t\tName: \"users\",\n\t\t\t\tColumns: []*schema.Column{\n\t\t\t\t\t{\n\t\t\t\t\t\tName: \"id\",\n\t\t\t\t\t\tType: &schema.ColumnType{Type: &schema.IntegerType{T: \"int\"}},\n\t\t\t\t\t\tAttrs: []schema.Attr{\n\t\t\t\t\t\t\t&AutoIncrement{},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\ts.Tables[0].Schema = s\n\ts.Tables[0].Schema = s\n\ts.Tables[0].Indexes = []*schema.Index{\n\t\t{\n\t\t\tName:   \"index\",\n\t\t\tTable:  s.Tables[0],\n\t\t\tUnique: true,\n\t\t\tParts: []*schema.IndexPart{\n\t\t\t\t{SeqNo: 0, C: s.Tables[0].Columns[0]},\n\t\t\t},\n\t\t\tAttrs: []schema.Attr{\n\t\t\t\t&IndexPredicate{P: \"id <> 0\"},\n\t\t\t},\n\t\t},\n\t}\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"id\" {\n    null           = false\n    type           = int\n    auto_increment = true\n  }\n  index \"index\" {\n    unique  = true\n    columns = [column.id]\n    where   = \"id <> 0\"\n  }\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestTypes(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\ttypeExpr string\n\t\texpected schema.Type\n\t}{\n\t\t{\n\t\t\ttypeExpr: \"integer(10)\",\n\t\t\texpected: &schema.IntegerType{T: \"integer\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int(10)\",\n\t\t\texpected: &schema.IntegerType{T: \"int\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: `sql(\"custom\")`,\n\t\t\texpected: &UserDefinedType{T: \"custom\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"tinyint(10)\",\n\t\t\texpected: &schema.IntegerType{T: \"tinyint\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"smallint(10)\",\n\t\t\texpected: &schema.IntegerType{T: \"smallint\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"mediumint(10)\",\n\t\t\texpected: &schema.IntegerType{T: \"mediumint\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"bigint(10)\",\n\t\t\texpected: &schema.IntegerType{T: \"bigint\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"unsigned_big_int(10)\",\n\t\t\texpected: &schema.IntegerType{T: \"unsigned big int\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int2(10)\",\n\t\t\texpected: &schema.IntegerType{T: \"int2\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"int8(10)\",\n\t\t\texpected: &schema.IntegerType{T: \"int8\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"uint64\",\n\t\t\texpected: &schema.IntegerType{T: \"uint64\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"real\",\n\t\t\texpected: &schema.FloatType{T: \"real\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"double\",\n\t\t\texpected: &schema.FloatType{T: \"double\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"double_precision\",\n\t\t\texpected: &schema.FloatType{T: \"double precision\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"float(10)\",\n\t\t\texpected: &schema.FloatType{T: \"float\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"text(10)\",\n\t\t\texpected: &schema.StringType{T: \"text\", Size: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"character(10)\",\n\t\t\texpected: &schema.StringType{T: \"character\", Size: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"varchar(10)\",\n\t\t\texpected: &schema.StringType{T: \"varchar\", Size: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"varying_character\",\n\t\t\texpected: &schema.StringType{T: \"varying character\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"nchar(10)\",\n\t\t\texpected: &schema.StringType{T: \"nchar\", Size: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"native_character\",\n\t\t\texpected: &schema.StringType{T: \"native character\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"nvarchar(10)\",\n\t\t\texpected: &schema.StringType{T: \"nvarchar\", Size: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"clob(10)\",\n\t\t\texpected: &schema.StringType{T: \"clob\", Size: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"blob(10)\",\n\t\t\texpected: &schema.BinaryType{T: \"blob\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"numeric(10)\",\n\t\t\texpected: &schema.DecimalType{T: \"numeric\", Precision: 10},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"decimal(10,5)\",\n\t\t\texpected: &schema.DecimalType{T: \"decimal\", Precision: 10, Scale: 5},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"boolean\",\n\t\t\texpected: &schema.BoolType{T: \"boolean\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"date\",\n\t\t\texpected: &schema.TimeType{T: \"date\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"datetime\",\n\t\t\texpected: &schema.TimeType{T: \"datetime\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"json\",\n\t\t\texpected: &schema.JSONType{T: \"json\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"uuid\",\n\t\t\texpected: &schema.UUIDType{T: \"uuid\"},\n\t\t},\n\t\t{\n\t\t\ttypeExpr: \"jsonb\",\n\t\t\texpected: &schema.JSONType{T: \"jsonb\"},\n\t\t},\n\t} {\n\t\tt.Run(tt.typeExpr, func(t *testing.T) {\n\t\t\tvar test schema.Schema\n\t\t\tdoc := fmt.Sprintf(`table \"test\" {\n\tschema = schema.test\n\tcolumn \"test\" {\n\t\tnull = false\n\t\ttype = %s\n\t}\n}\nschema \"test\" {\n}\n`, tt.typeExpr)\n\t\t\terr := EvalHCLBytes([]byte(doc), &test, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tcolspec := test.Tables[0].Columns[0]\n\t\t\trequire.EqualValues(t, tt.expected, colspec.Type.Type)\n\t\t\tspec, err := MarshalHCL(&test)\n\t\t\trequire.NoError(t, err)\n\t\t\tvar after schema.Schema\n\t\t\terr = EvalHCLBytes(spec, &after, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.EqualValues(t, tt.expected, after.Tables[0].Columns[0].Type.Type)\n\t\t})\n\t}\n}\n\nfunc TestMarshalSpec_TableOptions(t *testing.T) {\n\ts := schema.New(\"test\").\n\t\tAddTables(\n\t\t\tschema.NewTable(\"users\").\n\t\t\t\tAddColumns(\n\t\t\t\t\tschema.NewIntColumn(\"id\", \"int\"),\n\t\t\t\t).\n\t\t\t\tAddAttrs(\n\t\t\t\t\t&WithoutRowID{},\n\t\t\t\t\t&Strict{},\n\t\t\t\t),\n\t\t)\n\ts.Tables[0].SetSchema(s)\n\tbuf, err := MarshalHCL(s)\n\trequire.NoError(t, err)\n\tconst expected = `table \"users\" {\n  schema = schema.test\n  column \"id\" {\n    null = false\n    type = int\n  }\n  without_rowid = true\n  strict        = true\n}\nschema \"test\" {\n}\n`\n\trequire.EqualValues(t, expected, string(buf))\n}\n\nfunc TestInputVars(t *testing.T) {\n\tspectest.TestInputVars(t, EvalHCL)\n}\n"
  },
  {
    "path": "sql/sqlspec/sqlspec.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlspec\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\n\t\"github.com/hashicorp/hcl/v2\"\n\t\"github.com/zclconf/go-cty/cty\"\n)\n\ntype (\n\t// Schema holds a specification for a Schema.\n\tSchema struct {\n\t\tName string `spec:\"name,name\"`\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// Table holds a specification for an SQL table.\n\tTable struct {\n\t\tName        string         `spec:\",name\"`\n\t\tQualifier   string         `spec:\",qualifier\"`\n\t\tSchema      *schemahcl.Ref `spec:\"schema\"`\n\t\tColumns     []*Column      `spec:\"column\"`\n\t\tPrimaryKey  *PrimaryKey    `spec:\"primary_key\"`\n\t\tForeignKeys []*ForeignKey  `spec:\"foreign_key\"`\n\t\tIndexes     []*Index       `spec:\"index\"`\n\t\tChecks      []*Check       `spec:\"check\"`\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// View holds a specification for an SQL view.\n\tView struct {\n\t\tName      string         `spec:\",name\"`\n\t\tQualifier string         `spec:\",qualifier\"`\n\t\tSchema    *schemahcl.Ref `spec:\"schema\"`\n\t\tColumns   []*Column      `spec:\"column\"`\n\t\t// Indexes on (materialized) views are supported\n\t\t// by some databases, like PostgreSQL.\n\t\tIndexes []*Index `spec:\"index\"`\n\t\t// The definition is appended as additional attribute\n\t\t// by the spec creator to marshal it after the columns.\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// Column holds a specification for a column in an SQL table.\n\tColumn struct {\n\t\tName string          `spec:\",name\"`\n\t\tNull bool            `spec:\"null\"`\n\t\tType *schemahcl.Type `spec:\"type\"`\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// PrimaryKey holds a specification for the primary key of a table.\n\tPrimaryKey struct {\n\t\tName    string           `spec:\",name\"` // Optional name.\n\t\tParts   []*IndexPart     `spec:\"on\"`\n\t\tColumns []*schemahcl.Ref `spec:\"columns\"`\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// Index holds a specification for the index key of a table.\n\tIndex struct {\n\t\tName    string           `spec:\",name\"`\n\t\tUnique  bool             `spec:\"unique,omitempty\"`\n\t\tParts   []*IndexPart     `spec:\"on\"`\n\t\tColumns []*schemahcl.Ref `spec:\"columns\"`\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// IndexPart holds a specification for the index key part.\n\tIndexPart struct {\n\t\tDesc   bool           `spec:\"desc,omitempty\"`\n\t\tColumn *schemahcl.Ref `spec:\"column\"`\n\t\tExpr   string         `spec:\"expr,omitempty\"`\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// Check holds a specification for a check constraint on a table.\n\tCheck struct {\n\t\tName string `spec:\",name\"`\n\t\tExpr string `spec:\"expr\"`\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// ForeignKey holds a specification for the Foreign key of a table.\n\tForeignKey struct {\n\t\tSymbol     string           `spec:\",name\"`\n\t\tColumns    []*schemahcl.Ref `spec:\"columns\"`\n\t\tRefColumns []*schemahcl.Ref `spec:\"ref_columns\"`\n\t\tOnUpdate   *schemahcl.Ref   `spec:\"on_update\"`\n\t\tOnDelete   *schemahcl.Ref   `spec:\"on_delete\"`\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// Func holds the specification for a function.\n\tFunc struct {\n\t\tName      string         `spec:\",name\"`\n\t\tQualifier string         `spec:\",qualifier\"`\n\t\tSchema    *schemahcl.Ref `spec:\"schema\"`\n\t\tArgs      []*FuncArg     `spec:\"arg\"`\n\t\tLang      cty.Value      `spec:\"lang\"`\n\t\t// The definition and the return type are appended as additional\n\t\t// attribute by the spec creator to marshal it after the arguments.\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// FuncArg holds the specification for a function argument.\n\tFuncArg struct {\n\t\tName    string          `spec:\",name\"`\n\t\tType    *schemahcl.Type `spec:\"type\"`\n\t\tDefault cty.Value       `spec:\"default\"`\n\t\t// Optional attributes such as mode are added by the driver,\n\t\t// as their definition can be either a string or an enum (ref).\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// Trigger holds the specification for a trigger.\n\tTrigger struct {\n\t\tName string         `spec:\",name\"`\n\t\tOn   *schemahcl.Ref `spec:\"on\"` // A table or a view.\n\t\t// Attributes and blocks are different for each driver.\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n\n\t// Sequence holds a specification for a Sequence.\n\tSequence struct {\n\t\tName      string         `spec:\",name\"`\n\t\tQualifier string         `spec:\",qualifier\"`\n\t\tSchema    *schemahcl.Ref `spec:\"schema\"`\n\t\t// Type, Start, Increment, Min, Max, Cache, Cycle\n\t\t// are optionally added to the sequence definition.\n\t\tschemahcl.DefaultExtension\n\t\tRange *hcl.Range `spec:\",range\"`\n\t}\n)\n\n// Label returns the defaults label used for the table resource.\nfunc (t *Table) Label() string { return t.Name }\n\n// QualifierLabel returns the qualifier label used for the table resource, if any.\nfunc (t *Table) QualifierLabel() string { return t.Qualifier }\n\n// SetQualifier sets the qualifier label used for the table resource.\nfunc (t *Table) SetQualifier(q string) { t.Qualifier = q }\n\n// SchemaRef returns the schema reference for the table.\nfunc (t *Table) SchemaRef() *schemahcl.Ref { return t.Schema }\n\n// Label returns the defaults label used for the view resource.\nfunc (v *View) Label() string { return v.Name }\n\n// QualifierLabel returns the qualifier label used for the view resource, if any.\nfunc (v *View) QualifierLabel() string { return v.Qualifier }\n\n// SetQualifier sets the qualifier label used for the view resource.\nfunc (v *View) SetQualifier(q string) { v.Qualifier = q }\n\n// SchemaRef returns the schema reference for the view.\nfunc (v *View) SchemaRef() *schemahcl.Ref { return v.Schema }\n\n// Label returns the defaults label used for the function resource.\nfunc (f *Func) Label() string { return f.Name }\n\n// QualifierLabel returns the qualifier label used for the function resource, if any.\nfunc (f *Func) QualifierLabel() string { return f.Qualifier }\n\n// SetQualifier sets the qualifier label used for the function resource.\nfunc (f *Func) SetQualifier(q string) { f.Qualifier = q }\n\n// SchemaRef returns the schema reference for the function.\nfunc (f *Func) SchemaRef() *schemahcl.Ref { return f.Schema }\n\n// Label returns the defaults label used for the sequence resource.\nfunc (s *Sequence) Label() string { return s.Name }\n\n// QualifierLabel returns the qualifier label used for the sequence resource, if any.\nfunc (s *Sequence) QualifierLabel() string { return s.Qualifier }\n\n// SetQualifier sets the qualifier label used for the sequence resource.\nfunc (s *Sequence) SetQualifier(q string) { s.Qualifier = q }\n\n// SchemaRef returns the schema reference for the sequence.\nfunc (s *Sequence) SchemaRef() *schemahcl.Ref { return s.Schema }\n\nfunc init() {\n\tschemahcl.Register(\"view\", &View{})\n\tschemahcl.Register(\"materialized\", &View{})\n\tschemahcl.Register(\"table\", &Table{})\n\tschemahcl.Register(\"function\", &Func{})\n\tschemahcl.Register(\"procedure\", &Func{})\n\tschemahcl.Register(\"trigger\", &Trigger{})\n\tschemahcl.Register(\"sequence\", &Sequence{})\n\tschemahcl.Register(\"schema\", &Schema{})\n}\n\n// normalizeCRLF for heredoc strings that inspected and printed in the HCL as-is to\n// avoid having mixed endings in the printed file - Unix-like (default) and Windows-like.\nfunc normalizeCRLF(s string) string {\n\tif strings.Contains(s, \"\\r\\n\") {\n\t\treturn strings.ReplaceAll(s, \"\\r\\n\", \"\\n\")\n\t}\n\treturn s\n}\n\n// MightHeredoc returns the string as an indented heredoc if it has multiple lines.\nfunc MightHeredoc(s string) string {\n\ts = normalizeCRLF(strings.TrimSpace(s))\n\t// In case the given definition is multi-line,\n\t// format it as indented heredoc with two spaces.\n\tif lines := strings.Split(s, \"\\n\"); len(lines) > 1 {\n\t\tvar b bytes.Buffer\n\t\tb.Grow(len(s))\n\t\tb.WriteString(\"<<-SQL\\n\")\n\t\tfor _, l := range lines {\n\t\t\t// Skip spaces-only lines, as editors stripped these spaces off,\n\t\t\t// and HCL parser results a different string for them.\n\t\t\tif strings.TrimSpace(l) != \"\" {\n\t\t\t\tb.WriteString(\"  \")\n\t\t\t\tb.WriteString(l)\n\t\t\t}\n\t\t\tb.WriteByte('\\n')\n\t\t}\n\t\tb.WriteString(\"  SQL\")\n\t\ts = b.String()\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "sql/sqlspec/sqlspec_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqlspec\n\nimport (\n\t\"testing\"\n\n\t\"ariga.io/atlas/schemahcl\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestMightHeredoc(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tinput:    \"SELECT * FROM users\",\n\t\t\texpected: \"SELECT * FROM users\",\n\t\t},\n\t\t{\n\t\t\tinput: `\nSELECT\n  *\n  FROM users\n  WHERE active`,\n\t\t\texpected: `<<-SQL\n  SELECT\n    *\n    FROM users\n    WHERE active\n  SQL`,\n\t\t},\n\t\t{\n\t\t\tinput: `\n-- The line below includes spaces.\n  \n\t\nSELECT\n  *\n  FROM users\n  WHERE active`,\n\t\t\texpected: `<<-SQL\n  -- The line below includes spaces.\n\n\n  SELECT\n    *\n    FROM users\n    WHERE active\n  SQL`,\n\t\t},\n\t} {\n\t\trequire.Equal(t, tt.expected, MightHeredoc(tt.input))\n\t}\n}\n\nfunc TestMarshalPrimaryKey(t *testing.T) {\n\tspec := &Table{\n\t\tName: \"users\",\n\t\tColumns: []*Column{\n\t\t\t{Name: \"id\", Type: &schemahcl.Type{T: \"text\"}},\n\t\t},\n\t\tPrimaryKey: &PrimaryKey{\n\t\t\tColumns: []*schemahcl.Ref{\n\t\t\t\t{V: \"$column.id\"},\n\t\t\t},\n\t\t},\n\t}\n\tbuf, err := schemahcl.Marshal.MarshalSpec(spec)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `table \"users\" {\n  column \"id\" {\n    null = false\n    type = sql(\"text\")\n  }\n  primary_key {\n    columns = [column.id]\n  }\n}\n`, string(buf))\n\n\t// Include primary key on marshaling.\n\tspec.PrimaryKey.Name = \"custom_name\"\n\tbuf, err = schemahcl.Marshal.MarshalSpec(spec)\n\trequire.NoError(t, err)\n\trequire.Equal(t, `table \"users\" {\n  column \"id\" {\n    null = false\n    type = sql(\"text\")\n  }\n  primary_key \"custom_name\" {\n    columns = [column.id]\n  }\n}\n`, string(buf))\n}\n"
  },
  {
    "path": "sql/sqltool/doc.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n// Package sqltool contains logic to integrate existing tools like Flyway or Liquibase with the Atlas CLI.\npackage sqltool\n"
  },
  {
    "path": "sql/sqltool/hidden.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\n//go:build !windows\n\npackage sqltool\n\nimport \"path/filepath\"\n\nfunc hidden(path string) (bool, error) {\n\treturn filepath.Base(path)[0] == '.', nil\n}\n"
  },
  {
    "path": "sql/sqltool/hidden_windows.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqltool\n\nimport (\n\t\"path/filepath\"\n\t\"syscall\"\n)\n\nfunc hidden(path string) (bool, error) {\n\tabs, err := filepath.Abs(path)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tp, err := syscall.UTF16PtrFromString(abs)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tattr, err := syscall.GetFileAttributes(p)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn attr&syscall.FILE_ATTRIBUTE_HIDDEN != 0, nil\n}\n"
  },
  {
    "path": "sql/sqltool/testdata/dbmate/1_initial.sql",
    "content": "-- migrate:up\nCREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\n\n/*\n Multiline comment ...\n */\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\n\nINSERT INTO post (title) VALUES (\n'This is\nmy multiline\n\nvalue');\n\n-- migrate:down\n\n\nDROP TABLE post;"
  },
  {
    "path": "sql/sqltool/testdata/dbmate/2_second_migration.sql",
    "content": "\n\n\n-- migrate:up\n\n\n\n\nCREATE TABLE tbl_2 (col INT);"
  },
  {
    "path": "sql/sqltool/testdata/flyway/B2__baseline.sql",
    "content": "CREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    created_at TIMESTAMP NOT NULL\n    PRIMARY KEY (id)\n);\n\nINSERT INTO post (title, created_at) VALUES (\n'This is\nmy multiline\n\nvalue', NOW());"
  },
  {
    "path": "sql/sqltool/testdata/flyway/R__views.sql",
    "content": "CREATE VIEW `my_view` AS SELECT * FROM `post`;"
  },
  {
    "path": "sql/sqltool/testdata/flyway/U1__initial.sql",
    "content": "DROP TABLE tbl;"
  },
  {
    "path": "sql/sqltool/testdata/flyway/V1__initial.sql",
    "content": "-- comment\nCREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\n\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\n\nINSERT INTO post (title, created_at) VALUES (\n'This is\nmy multiline\n\nvalue', NOW());\n"
  },
  {
    "path": "sql/sqltool/testdata/flyway/V2__second_migration.sql",
    "content": "\n\n\n-- migrate:up\n\n\n\n\nCREATE TABLE tbl_2 (col INT);"
  },
  {
    "path": "sql/sqltool/testdata/flyway/V3__third_migration.sql",
    "content": "ALTER TABLE tbl_2 ADD col_1 INTEGER NOT NULL;"
  },
  {
    "path": "sql/sqltool/testdata/flyway/v3/V3_1__fourth_migration.sql",
    "content": "ALTER TABLE tbl_2 ADD col_2 INTEGER NOT NULL;"
  },
  {
    "path": "sql/sqltool/testdata/golang-migrate/1_initial.down.sql",
    "content": "DROP TABLE tbl;"
  },
  {
    "path": "sql/sqltool/testdata/golang-migrate/1_initial.up.sql",
    "content": "CREATE TABLE tbl\n(\n    col INT\n);"
  },
  {
    "path": "sql/sqltool/testdata/golang-migrate/2_second_migration.down.sql",
    "content": "DROP TABLE tbl_2;"
  },
  {
    "path": "sql/sqltool/testdata/golang-migrate/2_second_migration.up.sql",
    "content": "CREATE TABLE tbl_2 (col INT);"
  },
  {
    "path": "sql/sqltool/testdata/goose/1_initial.sql",
    "content": "-- +goose Up\nCREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\n\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\n\nINSERT INTO post (title) VALUES (\n'This is\nmy multiline\n\nvalue');\n\n-- +goose Down\nDROP TABLE post;"
  },
  {
    "path": "sql/sqltool/testdata/goose/2_second_migration.sql",
    "content": "\n\n\n-- +goose Up\n\n\nALTER TABLE post ADD updated_at TIMESTAMP NOT NULL;\n\n-- +goose StatementBegin\n-- Comment for the function declaration.\nCREATE\nOR REPLACE FUNCTION histories_partition_creation( DATE, DATE )\nreturns void AS $$\nDECLARE\ncreate_query text;\nBEGIN\nFOR create_query IN\nSELECT 'CREATE TABLE IF NOT EXISTS histories_'\n           || TO_CHAR(d, 'YYYY_MM')\n           || ' ( CHECK( created_at >= timestamp '''\n           || TO_CHAR(d, 'YYYY-MM-DD 00:00:00')\n           || ''' AND created_at < timestamp '''\n           || TO_CHAR(d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00')\n           || ''' ) ) inherits ( histories );'\nFROM generate_series($1, $2, '1 month') AS d LOOP\n    EXECUTE create_query;\nEND LOOP;  -- LOOP END\nEND;         -- FUNCTION END\n$$\nlanguage plpgsql;\n-- +goose StatementEnd"
  },
  {
    "path": "sql/sqltool/testdata/liquibase/1_initial.sql",
    "content": "--liquibase formatted sql\n\n--changeset atlas:1-1\nCREATE TABLE post\n(\n    id    int NOT NULL,\n    title text,\n    body  text,\n    PRIMARY KEY (id)\n);\n--rollback: DROP TABLE post;\n\n--changeset atlas:1-2\nALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\n--rollback: ALTER TABLE post DROP created_at;\n\n--changeset atlas:1-3\nINSERT INTO post (title) VALUES (\n'This is\nmy multiline\n\nvalue');\n"
  },
  {
    "path": "sql/sqltool/testdata/liquibase/2_second_migration.sql",
    "content": "--liquibase formatted sql\n\n--changeset atlas:2-1\nCREATE TABLE tbl_2 (col INT);\n--rollback DROP TABLE tbl_2;\n"
  },
  {
    "path": "sql/sqltool/tool.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqltool\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"slices\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"text/template\"\n\t\"time\"\n\t\"unicode\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n)\n\nvar (\n\t// GolangMigrateFormatter returns migrate.Formatter compatible with golang-migrate/migrate.\n\tGolangMigrateFormatter = templateFormatter(\n\t\t\"{{ now }}{{ with .Name }}_{{ . }}{{ end }}.up.sql\",\n\t\t`{{ range .Changes }}{{ with .Comment }}-- {{ println . }}{{ end }}{{ printf \"%s;\\n\" .Cmd }}{{ end }}`,\n\t\t\"{{ now }}{{ with .Name }}_{{ . }}{{ end }}.down.sql\",\n\t\t`{{ range $c := rev .Changes }}{{ with $stmts := .ReverseStmts }}{{ with $c.Comment }}-- reverse: {{ println . }}{{ end }}{{ range $stmts }}{{ printf \"%s;\\n\" . }}{{ end }}{{ end }}{{ end }}`,\n\t)\n\t// GooseFormatter returns migrate.Formatter compatible with pressly/goose.\n\tGooseFormatter = templateFormatter(\n\t\t\"{{ now }}{{ with .Name }}_{{ . }}{{ end }}.sql\",\n\t\t`-- +goose Up\n{{ range .Changes }}{{ with .Comment }}-- {{ println . }}{{ end }}{{ printf \"%s;\\n\" .Cmd }}{{ end }}\n-- +goose Down\n{{ range $c := rev .Changes }}{{ with $stmts := .ReverseStmts }}{{ with $c.Comment }}-- reverse: {{ println . }}{{ end }}{{ range $stmts }}{{ printf \"%s;\\n\" . }}{{ end }}{{ end }}{{ end }}`,\n\t)\n\t// FlywayFormatter returns migrate.Formatter compatible with Flyway.\n\tFlywayFormatter = templateFormatter(\n\t\t\"V{{ now }}{{ with .Name }}__{{ . }}{{ end }}.sql\",\n\t\t`{{ range .Changes }}{{ with .Comment }}-- {{ println . }}{{ end }}{{ printf \"%s;\\n\" .Cmd }}{{ end }}`,\n\t\t\"U{{ now }}{{ with .Name }}__{{ . }}{{ end }}.sql\",\n\t\t`{{ range $c := rev .Changes }}{{ with $stmts := .ReverseStmts }}{{ with $c.Comment }}-- reverse: {{ println . }}{{ end }}{{ range $stmts }}{{ printf \"%s;\\n\" . }}{{ end }}{{ end }}{{ end }}`,\n\t)\n\t// LiquibaseFormatter returns migrate.Formatter compatible with Liquibase.\n\tLiquibaseFormatter = templateFormatter(\n\t\t\"{{ now }}{{ with .Name }}_{{ . }}{{ end }}.sql\",\n\t\t`{{- $now := now -}}\n--liquibase formatted sql\n\n{{- range $index, $change := .Changes }}\n--changeset atlas:{{ $now }}-{{ inc $index }}\n{{ with $change.Comment }}--comment: {{ . }}{{ end }}\n{{ $change.Cmd }};\n{{ with $stmts := .ReverseStmts }}{{ range $stmts }}{{ printf \"--rollback: %s;\\n\" . }}{{ end }}{{ end }}\n{{- end }}`,\n\t)\n\t// DBMateFormatter returns migrate.Formatter compatible with amacneil/dbmate.\n\tDBMateFormatter = templateFormatter(\n\t\t\"{{ now }}{{ with .Name }}_{{ . }}{{ end }}.sql\",\n\t\t`-- migrate:up\n{{ range .Changes }}{{ with .Comment }}-- {{ println . }}{{ end }}{{ printf \"%s;\\n\" .Cmd }}{{ end }}\n-- migrate:down\n{{ range $c := rev .Changes }}{{ with $stmts := .ReverseStmts }}{{ with $c.Comment }}-- reverse: {{ println . }}{{ end }}{{ range $stmts }}{{ printf \"%s;\\n\" . }}{{ end }}{{ end }}{{ end }}`,\n\t)\n\t// DbmateFormatter is the same as DBMateFormatter.\n\t// Deprecated: Use DBMateFormatter instead.\n\tDbmateFormatter = DBMateFormatter\n)\n\ntype (\n\t// GolangMigrateDir wraps fs.FS and provides a migrate.Scanner implementation able to understand files\n\t// generated by the GolangMigrateFormatter for migration directory replaying.\n\tGolangMigrateDir struct{ fs.FS }\n\t// GolangMigrateFile wraps migrate.LocalFile with custom description function.\n\tGolangMigrateFile struct{ *migrate.LocalFile }\n)\n\n// NewGolangMigrateDir returns a new GolangMigrateDir.\nfunc NewGolangMigrateDir(path string) (*GolangMigrateDir, error) {\n\tdir, err := migrate.NewLocalDir(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &GolangMigrateDir{dir}, nil\n}\n\n// Path returns the local path used for opening this dir.\nfunc (d *GolangMigrateDir) Path() string {\n\tif dir, ok := d.FS.(dirPath); ok {\n\t\treturn dir.Path()\n\t}\n\treturn \"\"\n}\n\n// Files implements Scanner.Files. It looks for all files with up.sql suffix and orders them by filename.\nfunc (d *GolangMigrateDir) Files() ([]migrate.File, error) {\n\tnames, err := fs.Glob(d, \"*.up.sql\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// Sort files lexicographically.\n\tsort.Slice(names, func(i, j int) bool {\n\t\treturn names[i] < names[j]\n\t})\n\tret := make([]migrate.File, len(names))\n\tfor i, n := range names {\n\t\tb, err := fs.ReadFile(d, n)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sql/migrate: read file %q: %w\", n, err)\n\t\t}\n\t\tret[i] = &GolangMigrateFile{LocalFile: migrate.NewLocalFile(n, b)}\n\t}\n\treturn ret, nil\n}\n\n// Checksum implements Dir.Checksum. By default, it calls Files() and creates a checksum from them.\nfunc (d *GolangMigrateDir) Checksum() (migrate.HashFile, error) {\n\tfiles, err := d.Files()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn migrate.NewHashFile(files)\n}\n\n// WriteFile implements Dir.WriteFile.\nfunc (d *GolangMigrateDir) WriteFile(name string, b []byte) error {\n\tif d, ok := d.FS.(migrate.Dir); ok {\n\t\treturn d.WriteFile(name, b)\n\t}\n\treturn errors.New(\"sql/sqltool: write not supported\")\n}\n\n// Desc implements File.Desc.\nfunc (f *GolangMigrateFile) Desc() string {\n\treturn strings.TrimSuffix(f.LocalFile.Desc(), \".up\")\n}\n\ntype (\n\t// GooseDir wraps migrate.LocalDir and provides a migrate.Scanner implementation able to understand files\n\t// generated by the GooseFormatter for migration directory replaying.\n\tGooseDir struct{ *migrate.LocalDir }\n\t// GooseFile wraps migrate.LocalFile with custom statements function.\n\tGooseFile struct{ *migrate.LocalFile }\n)\n\n// NewGooseDir returns a new GooseDir.\nfunc NewGooseDir(path string) (*GooseDir, error) {\n\tdir, err := migrate.NewLocalDir(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &GooseDir{dir}, nil\n}\n\n// Files looks for all files with .sql suffix and orders them by filename.\nfunc (d *GooseDir) Files() ([]migrate.File, error) {\n\tfiles, err := d.LocalDir.Files()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor i, f := range files {\n\t\tfiles[i] = &GooseFile{f.(*migrate.LocalFile)}\n\t}\n\treturn files, nil\n}\n\n// StmtDecls understands the migration format used by pressly/goose sql migration files.\nfunc (f *GooseFile) StmtDecls() ([]*migrate.Stmt, error) {\n\t// Atlas custom delimiter is per file, goose has pragma do mark start and end of a delimiter.\n\t// In order to use the Atlas lexer, we define a custom delimiter for the source SQL and edit it to use the\n\t// custom delimiter.\n\tconst delim = \"-- ATLAS_DELIM_END\"\n\tvar (\n\t\tstate, lineCount int\n\t\tlines            = []string{\"-- atlas:delimiter \" + delim, \"\"}\n\t\tsc               = bufio.NewScanner(bytes.NewReader(f.Bytes()))\n\t)\nScan:\n\tfor sc.Scan() {\n\t\tlineCount++\n\t\tline := sc.Text()\n\t\t// Handle goose custom delimiters.\n\t\tif strings.HasPrefix(line, goosePragma) {\n\t\t\tswitch strings.TrimSpace(strings.TrimPrefix(line, goosePragma)) {\n\t\t\tcase \"Up\":\n\t\t\t\tswitch state {\n\t\t\t\tcase none: // found the \"up\" part of the file\n\t\t\t\t\tstate = up\n\t\t\t\tdefault:\n\t\t\t\t\treturn nil, unexpectedPragmaErr(f, lineCount, \"Up\")\n\t\t\t\t}\n\t\t\tcase \"Down\":\n\t\t\t\tswitch state {\n\t\t\t\tcase up: // found the \"down\" part\n\t\t\t\t\tbreak Scan\n\t\t\t\tdefault:\n\t\t\t\t\treturn nil, unexpectedPragmaErr(f, lineCount, \"Down\")\n\t\t\t\t}\n\t\t\tcase \"StatementBegin\":\n\t\t\t\tswitch state {\n\t\t\t\tcase up:\n\t\t\t\t\tstate = begin // begin of a statement\n\t\t\t\tdefault:\n\t\t\t\t\treturn nil, unexpectedPragmaErr(f, lineCount, \"StatementBegin\")\n\t\t\t\t}\n\t\t\tcase \"StatementEnd\":\n\t\t\t\tswitch state {\n\t\t\t\tcase begin:\n\t\t\t\t\tstate = end // end of a statement\n\t\t\t\tdefault:\n\t\t\t\t\treturn nil, unexpectedPragmaErr(f, lineCount, \"StatementEnd\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Write the line of the statement.\n\t\tif !reGoosePragma.MatchString(line) && state != end {\n\t\t\t// end of statement if line ends with semicolon\n\t\t\tline = strings.TrimRightFunc(line, unicode.IsSpace)\n\t\t\tlines = append(lines, line)\n\t\t\tif state == up && strings.HasSuffix(line, \";\") && !strings.HasPrefix(line, \"--\") {\n\t\t\t\tlines = append(lines, delim)\n\t\t\t}\n\t\t}\n\t\tif state == end {\n\t\t\tstate = up\n\t\t\tlines = append(lines, delim)\n\t\t}\n\t}\n\treturn migrate.Stmts(strings.Join(lines, \"\\n\"))\n}\n\n// Stmts understands the migration format used by pressly/goose sql migration files.\nfunc (f *GooseFile) Stmts() ([]string, error) {\n\ts, err := f.StmtDecls()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tstmts := make([]string, len(s))\n\tfor i := range s {\n\t\tstmts[i] = s[i].Text\n\t}\n\treturn stmts, nil\n}\n\ntype (\n\t// DBMateDir wraps migrate.LocalDir and provides a migrate.Scanner implementation able to understand files\n\t// generated by the DBMateFormatter for migration directory replaying.\n\tDBMateDir struct{ *migrate.LocalDir }\n\t// DBMateFile wraps migrate.LocalFile with custom statements function.\n\tDBMateFile struct{ *migrate.LocalFile }\n)\n\n// NewDBMateDir returns a new DBMateDir.\nfunc NewDBMateDir(path string) (*DBMateDir, error) {\n\tdir, err := migrate.NewLocalDir(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &DBMateDir{dir}, nil\n}\n\n// Files looks for all files with up.sql suffix and orders them by filename.\nfunc (d *DBMateDir) Files() ([]migrate.File, error) {\n\tfiles, err := d.LocalDir.Files()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tfor i, f := range files {\n\t\tfiles[i] = &DBMateFile{f.(*migrate.LocalFile)}\n\t}\n\treturn files, nil\n}\n\n// StmtDecls understands the migration format used by amacneil/dbmate sql migration files.\nfunc (f *DBMateFile) StmtDecls() ([]*migrate.Stmt, error) {\n\tvar (\n\t\tstate, lineCount int\n\t\tlines            []string\n\t\tsc               = bufio.NewScanner(bytes.NewReader(f.Bytes()))\n\t)\nScan:\n\tfor sc.Scan() {\n\t\tlineCount++\n\t\tline := sc.Text()\n\t\t// Handle pragmas.\n\t\tif strings.HasPrefix(line, dbmatePragma) {\n\t\t\tswitch strings.TrimSpace(strings.TrimPrefix(line, dbmatePragma)) {\n\t\t\tcase \"up\":\n\t\t\t\tstate = up\n\t\t\tcase \"down\":\n\t\t\t\tbreak Scan\n\t\t\t}\n\t\t}\n\t\t// Write the line of the statement.\n\t\tif !reDBMatePragma.MatchString(line) && state == up {\n\t\t\tlines = append(lines, line)\n\t\t}\n\t}\n\treturn migrate.Stmts(strings.Join(lines, \"\\n\"))\n}\n\n// Stmts understands the migration format used by amacneil/dbmate sql migration files.\nfunc (f *DBMateFile) Stmts() ([]string, error) {\n\ts, err := f.StmtDecls()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tstmts := make([]string, len(s))\n\tfor i := range s {\n\t\tstmts[i] = s[i].Text\n\t}\n\treturn stmts, nil\n}\n\ntype (\n\t// FlywayDir wraps fs.FS and provides a migrate.Scanner implementation able to understand files\n\t// generated by the FlywayFormatter for migration directory replaying.\n\tFlywayDir struct{ fs.FS }\n\t// FlywayFile wraps migrate.LocalFile with custom statements function.\n\tFlywayFile struct{ *migrate.LocalFile }\n)\n\n// NewFlywayDir returns a new FlywayDir.\nfunc NewFlywayDir(path string) (*FlywayDir, error) {\n\tdir, err := migrate.NewLocalDir(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &FlywayDir{dir}, nil\n}\n\n// Path returns the local path used for opening this dir.\nfunc (d *FlywayDir) Path() string {\n\tif dir, ok := d.FS.(dirPath); ok {\n\t\treturn dir.Path()\n\t}\n\treturn \"\"\n}\n\n// Files implements Scanner.Files. It looks for all files with .sql suffix. The given directory is recursively scanned\n// for non-hidden subdirectories. All found files will be ordered by migration type (Baseline, Versioned, Repeatable)\n// and filename.\nfunc (d *FlywayDir) Files() ([]migrate.File, error) {\n\tvar ff flywayFiles\n\tif err := fs.WalkDir(d, \".\", func(path string, e fs.DirEntry, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif path != \".\" && e.IsDir() {\n\t\t\tfullPath := path\n\t\t\tif p, ok := d.FS.(dirPath); ok {\n\t\t\t\tfullPath = filepath.Join(p.Path(), path)\n\t\t\t}\n\t\t\th, err := hidden(fullPath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif h {\n\t\t\t\treturn fs.SkipDir\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tvar (\n\t\t\tpfx  = e.Name()[0]\n\t\t\tbase = filepath.Base(e.Name())\n\t\t\text  = filepath.Ext(e.Name())\n\t\t)\n\t\tif ext != \".sql\" || len(base) < 4 || (pfx != 'V' && pfx != 'B' && pfx != 'R') {\n\t\t\treturn nil\n\t\t}\n\t\treturn ff.add(path)\n\t}); err != nil {\n\t\treturn nil, err\n\t}\n\tvar (\n\t\tnames = ff.names()\n\t\tret   = make([]migrate.File, len(names))\n\t)\n\tfor i, n := range names {\n\t\tb, err := fs.ReadFile(d, n)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"sql/migrate: read file %q: %w\", n, err)\n\t\t}\n\t\tret[i] = &FlywayFile{migrate.NewLocalFile(n, b)}\n\t}\n\treturn ret, nil\n}\n\n// Checksum implements Dir.Checksum. By default, it calls Files() and creates a checksum from them.\nfunc (d *FlywayDir) Checksum() (migrate.HashFile, error) {\n\tfiles, err := d.Files()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn migrate.NewHashFile(files)\n}\n\n// WriteFile implements Dir.WriteFile.\nfunc (d *FlywayDir) WriteFile(name string, b []byte) error {\n\tif d, ok := d.FS.(migrate.Dir); ok {\n\t\treturn d.WriteFile(name, b)\n\t}\n\treturn errors.New(\"sql/sqltool: write not supported\")\n}\n\n// Desc implements File.Desc.\nfunc (f FlywayFile) Desc() string {\n\treturn flywayDesc(f.Name())\n}\n\n// Version implements File.Version.\nfunc (f FlywayFile) Version() string {\n\treturn flywayVersion(f.Name())\n}\n\n// SetRepeatableVersion iterates over the migration files and assigns repeatable migrations a version number since\n// Atlas does not have the concept of repeatable migrations. Each repeatable migration file gets assigned the version\n// of the preceding migration file (or 0) followed by an 'R'.\nfunc SetRepeatableVersion(ff []migrate.File) {\n\t// First find the index of the first repeatable migration file (if any).\n\tvar (\n\t\tv   string // last versioned migration version\n\t\tidx = func() int {\n\t\t\tfor i, f := range ff {\n\t\t\t\tif f.Version() == \"\" {\n\t\t\t\t\treturn i\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1\n\t\t}()\n\t)\n\tswitch idx {\n\tcase -1:\n\t\t// No repeatable migration does exist.\n\t\treturn\n\tcase 0:\n\t\t// There is no preceding migration. Use Version \"0\".\n\t\tv = \"0\"\n\tdefault:\n\t\tv = ff[idx-1].Version()\n\t}\n\tif v != \"\" {\n\t\t// Every migration file following the first repeatable found are repeatable as well.\n\t\tfor i, f := range ff[idx:] {\n\t\t\tff[idx+i] = &FlywayFile{migrate.NewLocalFile(\n\t\t\t\tfmt.Sprintf(\"V%sR__%s\", v, f.Desc()),\n\t\t\t\tf.Bytes(),\n\t\t\t)}\n\t\t}\n\t}\n}\n\n// LiquibaseDir wraps migrate.LocalDir and provides a migrate.Scanner implementation able to understand files\n// generated by the LiquibaseFormatter for migration directory replaying.\ntype LiquibaseDir struct{ *migrate.LocalDir }\n\n// NewLiquibaseDir returns a new LiquibaseDir.\nfunc NewLiquibaseDir(path string) (*LiquibaseDir, error) {\n\td, err := migrate.NewLocalDir(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &LiquibaseDir{d}, nil\n}\n\nconst (\n\tnone int = iota\n\tup\n\tbegin\n\tend\n\tgoosePragma  = \"-- +goose\"\n\tdbmatePragma = \"-- migrate:\"\n)\n\nvar (\n\treGoosePragma  = regexp.MustCompile(regexp.QuoteMeta(goosePragma) + \" Up|Down|StatementBegin|StatementEnd\")\n\treDBMatePragma = regexp.MustCompile(dbmatePragma + \"up|down\")\n)\n\n// flywayFiles retrieves flyway migration files by calls to add(). It will only keep the latest baseline and ignore\n// all versioned files that are included in that baseline.\ntype flywayFiles struct {\n\tbaseline   string\n\tversioned  []string\n\trepeatable []string\n}\n\n// add the given path to the migration files according to its type. The input directory is assumed to be valid\n// according to the Flyway documentation (no duplicate versions, etc.).\nfunc (ff *flywayFiles) add(path string) error {\n\tswitch p := filepath.Base(path)[0]; p {\n\tcase 'B':\n\t\tif ff.baseline != \"\" && flywayVersion(path) < flywayVersion(ff.baseline) {\n\t\t\treturn nil\n\t\t}\n\t\tff.baseline = path\n\t\t// In case we set a new baseline, remove all versioned files with a version smaller than the new baseline.\n\t\tvar (\n\t\t\tbv = flywayVersion(ff.baseline)\n\t\t\tvs []string\n\t\t)\n\t\tfor _, v := range ff.versioned {\n\t\t\tif v > bv {\n\t\t\t\tvs = append(vs, v)\n\t\t\t}\n\t\t}\n\t\tff.versioned = vs\n\t\treturn nil\n\tcase 'V':\n\t\tv := flywayVersion(path)\n\t\tif ff.baseline == \"\" || flywayVersion(ff.baseline) < v {\n\t\t\tff.versioned = append(ff.versioned, path)\n\t\t}\n\t\treturn nil\n\tcase 'R':\n\t\tff.repeatable = append(ff.repeatable, path)\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"sql/sqltool: unexpected Flyway prefix %q\", p)\n\t}\n}\n\nfunc (ff *flywayFiles) names() []string {\n\tvar names []string\n\tif ff.baseline != \"\" {\n\t\tnames = append(names, ff.baseline)\n\t}\n\tflywaySort(ff.versioned)\n\tflywaySort(ff.repeatable)\n\tnames = append(names, ff.versioned...)\n\tnames = append(names, ff.repeatable...)\n\treturn names\n}\n\nfunc flywayDesc(path string) string {\n\tparts := strings.SplitN(path, \"__\", 2)\n\tif len(parts) == 1 {\n\t\treturn \"\"\n\t}\n\treturn strings.TrimSuffix(parts[1], \".sql\")\n}\n\nfunc flywayVersion(path string) string {\n\t// Repeatable migrations don't have a version.\n\tif filepath.Base(path)[0] == 'R' {\n\t\treturn \"\"\n\t}\n\treturn strings.SplitN(strings.TrimSuffix(filepath.Base(path), \".sql\"), \"__\", 2)[0][1:]\n}\n\nfunc flywaySort(files []string) {\n\tsort.Slice(files, func(i, j int) bool {\n\t\treturn flywayVersionCompare(flywayVersion(files[i]), flywayVersion(files[j])) < 0\n\t})\n}\n\nfunc flywayVersionCompare(v1, v2 string) int {\n\tparse := func(s string) []int {\n\t\tss := strings.Split(strings.ReplaceAll(s, \"_\", \".\"), \".\")\n\t\tvar ret []int\n\t\tfor _, s := range ss {\n\t\t\t// 0 for non-numeric parts.\n\t\t\ti, _ := strconv.Atoi(s)\n\t\t\tret = append(ret, i)\n\t\t}\n\t\treturn ret\n\t}\n\treturn slices.Compare(parse(v1), parse(v2))\n}\n\nfunc unexpectedPragmaErr(f migrate.File, line int, pragma string) error {\n\tvar tool string\n\tswitch f := f.(type) {\n\tcase *GooseFile:\n\t\ttool = \"goose\"\n\tcase *DBMateFile:\n\t\ttool = \"dbmate\"\n\tdefault:\n\t\treturn fmt.Errorf(\"sql/migrate: unexpected migration file type '%T'\", f)\n\t}\n\treturn fmt.Errorf(\n\t\t\"sql/migrate: %s: %s:%d unexpected goosePragma '%s'\",\n\t\ttool, f.Name(), line, pragma,\n\t)\n}\n\n// funcs contains the template.FuncMap for the different formatters.\nvar funcs = template.FuncMap{\n\t\"inc\": func(x int) int { return x + 1 },\n\t// now formats the current time in a lexicographically ascending order while maintaining human readability.\n\t\"now\": func() string { return time.Now().UTC().Format(\"20060102150405\") },\n\t\"rev\": reverse,\n}\n\n// templateFormatter parses the given templates and passes them on to the migrate.NewTemplateFormatter.\nfunc templateFormatter(templates ...string) migrate.Formatter {\n\ttpls := make([]*template.Template, len(templates))\n\tfor i, t := range templates {\n\t\ttpls[i] = template.Must(template.New(\"\").Funcs(funcs).Parse(t))\n\t}\n\ttf, err := migrate.NewTemplateFormatter(tpls...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn tf\n}\n\n// reverse changes for the down migration.\nfunc reverse(changes []*migrate.Change) []*migrate.Change {\n\tn := len(changes)\n\trev := make([]*migrate.Change, n)\n\tif n%2 == 1 {\n\t\trev[n/2] = changes[n/2]\n\t}\n\tfor i, j := 0, n-1; i < j; i, j = i+1, j-1 {\n\t\trev[i], rev[j] = changes[j], changes[i]\n\t}\n\treturn rev\n}\n\ntype dirPath interface {\n\tPath() string\n}\n\nvar (\n\t_ dirPath = (*DBMateDir)(nil)\n\t_ dirPath = (*FlywayDir)(nil)\n\t_ dirPath = (*GolangMigrateDir)(nil)\n\t_ dirPath = (*GooseDir)(nil)\n\t_ dirPath = (*LiquibaseDir)(nil)\n)\n"
  },
  {
    "path": "sql/sqltool/tool_test.go",
    "content": "// Copyright 2021-present The Atlas Authors. All rights reserved.\n// This source code is licensed under the Apache 2.0 license found\n// in the LICENSE file in the root directory of this source tree.\n\npackage sqltool_test\n\nimport (\n\t\"fmt\"\n\t\"io/fs\"\n\t\"testing\"\n\t\"testing/fstest\"\n\t\"time\"\n\n\t\"ariga.io/atlas/sql/migrate\"\n\t\"ariga.io/atlas/sql/sqltool\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nvar plan = &migrate.Plan{\n\tName:       \"tooling-plan\",\n\tReversible: true,\n\tChanges: []*migrate.Change{\n\t\t{Cmd: \"CREATE TABLE t1(c int)\", Reverse: \"DROP TABLE t1 IF EXISTS\", Comment: \"create table t1\"},\n\t\t{Cmd: \"CREATE TABLE t2(c int)\", Reverse: \"DROP TABLE t2\", Comment: \"create table t2\"},\n\t\t{Cmd: \"DROP TABLE t3\", Reverse: []string{\"CREATE TABLE t1(id int)\", \"CREATE INDEX idx ON t1(id)\"}, Comment: \"drop table t3\"},\n\t},\n}\n\nfunc TestFormatters(t *testing.T) {\n\tv := time.Now().UTC().Format(\"20060102150405\")\n\tfor _, tt := range []struct {\n\t\tname     string\n\t\tfmt      migrate.Formatter\n\t\texpected map[string]string\n\t}{\n\t\t{\n\t\t\t\"golang-migrate/migrate\",\n\t\t\tsqltool.GolangMigrateFormatter,\n\t\t\tmap[string]string{\n\t\t\t\tv + \"_tooling-plan.up.sql\": `-- create table t1\nCREATE TABLE t1(c int);\n-- create table t2\nCREATE TABLE t2(c int);\n-- drop table t3\nDROP TABLE t3;\n`,\n\t\t\t\tv + \"_tooling-plan.down.sql\": `-- reverse: drop table t3\nCREATE TABLE t1(id int);\nCREATE INDEX idx ON t1(id);\n-- reverse: create table t2\nDROP TABLE t2;\n-- reverse: create table t1\nDROP TABLE t1 IF EXISTS;\n`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"pressly/goose\",\n\t\t\tsqltool.GooseFormatter,\n\t\t\tmap[string]string{\n\t\t\t\tv + \"_tooling-plan.sql\": `-- +goose Up\n-- create table t1\nCREATE TABLE t1(c int);\n-- create table t2\nCREATE TABLE t2(c int);\n-- drop table t3\nDROP TABLE t3;\n\n-- +goose Down\n-- reverse: drop table t3\nCREATE TABLE t1(id int);\nCREATE INDEX idx ON t1(id);\n-- reverse: create table t2\nDROP TABLE t2;\n-- reverse: create table t1\nDROP TABLE t1 IF EXISTS;\n`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"flyway\",\n\t\t\tsqltool.FlywayFormatter,\n\t\t\tmap[string]string{\n\t\t\t\t\"V\" + v + \"__tooling-plan.sql\": `-- create table t1\nCREATE TABLE t1(c int);\n-- create table t2\nCREATE TABLE t2(c int);\n-- drop table t3\nDROP TABLE t3;\n`,\n\t\t\t\t\"U\" + v + \"__tooling-plan.sql\": `-- reverse: drop table t3\nCREATE TABLE t1(id int);\nCREATE INDEX idx ON t1(id);\n-- reverse: create table t2\nDROP TABLE t2;\n-- reverse: create table t1\nDROP TABLE t1 IF EXISTS;\n`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"liquibase\",\n\t\t\tsqltool.LiquibaseFormatter,\n\t\t\tmap[string]string{\n\t\t\t\tv + \"_tooling-plan.sql\": fmt.Sprintf(`--liquibase formatted sql\n--changeset atlas:%[1]s-1\n--comment: create table t1\nCREATE TABLE t1(c int);\n--rollback: DROP TABLE t1 IF EXISTS;\n\n--changeset atlas:%[1]s-2\n--comment: create table t2\nCREATE TABLE t2(c int);\n--rollback: DROP TABLE t2;\n\n--changeset atlas:%[1]s-3\n--comment: drop table t3\nDROP TABLE t3;\n--rollback: CREATE TABLE t1(id int);\n--rollback: CREATE INDEX idx ON t1(id);\n`, v),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"amacneil/dbmate\",\n\t\t\tsqltool.DBMateFormatter,\n\t\t\tmap[string]string{\n\t\t\t\tv + \"_tooling-plan.sql\": `-- migrate:up\n-- create table t1\nCREATE TABLE t1(c int);\n-- create table t2\nCREATE TABLE t2(c int);\n-- drop table t3\nDROP TABLE t3;\n\n-- migrate:down\n-- reverse: drop table t3\nCREATE TABLE t1(id int);\nCREATE INDEX idx ON t1(id);\n-- reverse: create table t2\nDROP TABLE t2;\n-- reverse: create table t1\nDROP TABLE t1 IF EXISTS;\n`,\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\td := dir(t)\n\t\t\tpl := migrate.NewPlanner(nil, d, migrate.PlanFormat(tt.fmt), migrate.PlanWithChecksum(false))\n\t\t\trequire.NotNil(t, pl)\n\t\t\trequire.NoError(t, pl.WritePlan(plan))\n\t\t\trequire.Equal(t, len(tt.expected), countFiles(t, d))\n\t\t\tfor name, content := range tt.expected {\n\t\t\t\trequireFileEqual(t, d, name, content)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestScanners(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname                   string\n\t\tdir                    migrate.Dir\n\t\tversions, descriptions []string\n\t\tstmts                  [][]string\n\t}{\n\t\t{\n\t\t\tname: \"golang-migrate\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\td, err := sqltool.NewGolangMigrateDir(\"testdata/golang-migrate\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t}(),\n\t\t\tversions:     []string{\"1\", \"2\"},\n\t\t\tdescriptions: []string{\"initial\", \"second_migration\"},\n\t\t\tstmts: [][]string{\n\t\t\t\t{\"CREATE TABLE tbl\\n(\\n    col INT\\n);\"},\n\t\t\t\t{\"CREATE TABLE tbl_2 (col INT);\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"goose\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\td, err := sqltool.NewGooseDir(\"testdata/goose\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t}(),\n\t\t\tversions:     []string{\"1\", \"2\"},\n\t\t\tdescriptions: []string{\"initial\", \"second_migration\"},\n\t\t\tstmts: [][]string{\n\t\t\t\t{\n\t\t\t\t\t\"CREATE TABLE post\\n(\\n    id    int NOT NULL,\\n    title text,\\n    body  text,\\n    PRIMARY KEY (id)\\n);\",\n\t\t\t\t\t\"ALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\",\n\t\t\t\t\t\"INSERT INTO post (title) VALUES (\\n'This is\\nmy multiline\\n\\nvalue');\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"ALTER TABLE post ADD updated_at TIMESTAMP NOT NULL;\",\n\t\t\t\t\t\"CREATE\\nOR REPLACE FUNCTION histories_partition_creation( DATE, DATE )\\nreturns void AS $$\\nDECLARE\\ncreate_query text;\\nBEGIN\\nFOR create_query IN\\nSELECT 'CREATE TABLE IF NOT EXISTS histories_'\\n           || TO_CHAR(d, 'YYYY_MM')\\n           || ' ( CHECK( created_at >= timestamp '''\\n           || TO_CHAR(d, 'YYYY-MM-DD 00:00:00')\\n           || ''' AND created_at < timestamp '''\\n           || TO_CHAR(d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00')\\n           || ''' ) ) inherits ( histories );'\\nFROM generate_series($1, $2, '1 month') AS d LOOP\\n    EXECUTE create_query;\\nEND LOOP;  -- LOOP END\\nEND;         -- FUNCTION END\\n$$\\nlanguage plpgsql;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"flyway\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\td, err := sqltool.NewFlywayDir(\"testdata/flyway\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t}(),\n\t\t\tversions:     []string{\"2\", \"3\", \"3_1\", \"\"},\n\t\t\tdescriptions: []string{\"baseline\", \"third_migration\", \"fourth_migration\", \"views\"},\n\t\t\tstmts: [][]string{\n\t\t\t\t{\n\t\t\t\t\t\"CREATE TABLE post\\n(\\n    id    int NOT NULL,\\n    title text,\\n    body  text,\\n    created_at TIMESTAMP NOT NULL\\n    PRIMARY KEY (id)\\n);\",\n\t\t\t\t\t\"INSERT INTO post (title, created_at) VALUES (\\n'This is\\nmy multiline\\n\\nvalue', NOW());\",\n\t\t\t\t},\n\t\t\t\t{\"ALTER TABLE tbl_2 ADD col_1 INTEGER NOT NULL;\"},\n\t\t\t\t{\"ALTER TABLE tbl_2 ADD col_2 INTEGER NOT NULL;\"},\n\t\t\t\t{\"CREATE VIEW `my_view` AS SELECT * FROM `post`;\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"liquibase\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\td, err := sqltool.NewLiquibaseDir(\"testdata/liquibase\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t}(),\n\t\t\tversions:     []string{\"1\", \"2\"},\n\t\t\tdescriptions: []string{\"initial\", \"second_migration\"},\n\t\t\tstmts: [][]string{\n\t\t\t\t{\n\t\t\t\t\t\"CREATE TABLE post\\n(\\n    id    int NOT NULL,\\n    title text,\\n    body  text,\\n    PRIMARY KEY (id)\\n);\",\n\t\t\t\t\t\"ALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\",\n\t\t\t\t\t\"INSERT INTO post (title) VALUES (\\n'This is\\nmy multiline\\n\\nvalue');\",\n\t\t\t\t},\n\t\t\t\t{\"CREATE TABLE tbl_2 (col INT);\"},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"dbmate\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\td, err := sqltool.NewDBMateDir(\"testdata/dbmate\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t}(),\n\t\t\tversions:     []string{\"1\", \"2\"},\n\t\t\tdescriptions: []string{\"initial\", \"second_migration\"},\n\t\t\tstmts: [][]string{\n\t\t\t\t{\n\t\t\t\t\t\"CREATE TABLE post\\n(\\n    id    int NOT NULL,\\n    title text,\\n    body  text,\\n    PRIMARY KEY (id)\\n);\",\n\t\t\t\t\t\"ALTER TABLE post ADD created_at TIMESTAMP NOT NULL;\",\n\t\t\t\t\t\"INSERT INTO post (title) VALUES (\\n'This is\\nmy multiline\\n\\nvalue');\",\n\t\t\t\t},\n\t\t\t\t{\"CREATE TABLE tbl_2 (col INT);\"},\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tfiles, err := tt.dir.Files()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, files, len(tt.versions))\n\t\t\tfor i := range tt.versions {\n\t\t\t\trequire.Equal(t, tt.versions[i], files[i].Version())\n\t\t\t\trequire.Equal(t, tt.descriptions[i], files[i].Desc())\n\t\t\t\tstmts, err := files[i].Stmts()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, stmts, len(tt.stmts[i]))\n\t\t\t\tfor j, stmt := range stmts {\n\t\t\t\t\trequire.Equal(t, tt.stmts[i][j], stmt)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestChecksum(t *testing.T) {\n\tfor _, tt := range []struct {\n\t\tname  string\n\t\tdir   migrate.Dir\n\t\tfiles []string // files expected to be part of the checksum (in order)\n\t}{\n\t\t{\n\t\t\tname: \"golang-migrate\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\td, err := sqltool.NewGolangMigrateDir(\"testdata/golang-migrate\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t}(),\n\t\t\tfiles: []string{\n\t\t\t\t\"1_initial.up.sql\",\n\t\t\t\t\"2_second_migration.up.sql\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"golang-migrate non-local directory\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\tfs := fstest.MapFS{\n\t\t\t\t\t\"1_initial.down.sql\":          &fstest.MapFile{Data: []byte(\"1_initial.down\")},\n\t\t\t\t\t\"1_initial.up.sql\":            &fstest.MapFile{Data: []byte(\"1_initial.up\")},\n\t\t\t\t\t\"2_second_migration.down.sql\": &fstest.MapFile{Data: []byte(\"2_second_migration.down\")},\n\t\t\t\t\t\"2_second_migration.up.sql\":   &fstest.MapFile{Data: []byte(\"2_second_migration.up\")},\n\t\t\t\t}\n\t\t\t\treturn &sqltool.GolangMigrateDir{&fs}\n\t\t\t}(),\n\t\t\tfiles: []string{\n\t\t\t\t\"1_initial.up.sql\",\n\t\t\t\t\"2_second_migration.up.sql\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"goose\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\td, err := sqltool.NewGooseDir(\"testdata/goose\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t}(),\n\t\t\tfiles: []string{\n\t\t\t\t\"1_initial.sql\",\n\t\t\t\t\"2_second_migration.sql\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"flyway\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\td, err := sqltool.NewFlywayDir(\"testdata/flyway\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t}(),\n\t\t\tfiles: []string{\n\t\t\t\t\"B2__baseline.sql\",\n\t\t\t\t\"V3__third_migration.sql\",\n\t\t\t\t\"v3/V3_1__fourth_migration.sql\",\n\t\t\t\t\"R__views.sql\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"flyway non-local directory\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\tfs := fstest.MapFS{\n\t\t\t\t\t\"U1__initial.sql\":               &fstest.MapFile{Data: []byte(\"U1__initial\")},\n\t\t\t\t\t\"V1__initial.sql\":               &fstest.MapFile{Data: []byte(\"V1__initial\")},\n\t\t\t\t\t\"R__views.sql\":                  &fstest.MapFile{Data: []byte(\"R__views\")},\n\t\t\t\t\t\"B2__baseline.sql\":              &fstest.MapFile{Data: []byte(\"B2__baseline\")},\n\t\t\t\t\t\"V2__second_migration.sql\":      &fstest.MapFile{Data: []byte(\"V2__second_migration\")},\n\t\t\t\t\t\"V3__third_migration.sql\":       &fstest.MapFile{Data: []byte(\"V3__third_migration\")},\n\t\t\t\t\t\"v3/V3_1__fourth_migration.sql\": &fstest.MapFile{Data: []byte(\"V3__1_fourth_migration\")},\n\t\t\t\t}\n\t\t\t\treturn &sqltool.FlywayDir{&fs}\n\t\t\t}(),\n\t\t\tfiles: []string{\n\t\t\t\t\"B2__baseline.sql\",\n\t\t\t\t\"V3__third_migration.sql\",\n\t\t\t\t\"v3/V3_1__fourth_migration.sql\",\n\t\t\t\t\"R__views.sql\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"flyway with semver versioning\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\tfs := fstest.MapFS{\n\t\t\t\t\t\"V1__.sql\":        &fstest.MapFile{Data: []byte(\"V1\")},\n\t\t\t\t\t\"V1_1_0__.sql\":    &fstest.MapFile{Data: []byte(\"V1.1.0\")},\n\t\t\t\t\t\"V1.1.1__.sql\":    &fstest.MapFile{Data: []byte(\"V1.1.1\")},\n\t\t\t\t\t\"V2__.sql\":        &fstest.MapFile{Data: []byte(\"V2\")},\n\t\t\t\t\t\"V2.1.0__.sql\":    &fstest.MapFile{Data: []byte(\"V2.1.0\")},\n\t\t\t\t\t\"V3__.sql\":        &fstest.MapFile{Data: []byte(\"V3\")},\n\t\t\t\t\t\"V11__.sql\":       &fstest.MapFile{Data: []byte(\"V11\")},\n\t\t\t\t\t\"V11.11.11__.sql\": &fstest.MapFile{Data: []byte(\"V11.11.11\")},\n\t\t\t\t}\n\t\t\t\treturn &sqltool.FlywayDir{&fs}\n\t\t\t}(),\n\t\t\tfiles: []string{\n\t\t\t\t\"V1__.sql\",\n\t\t\t\t\"V1_1_0__.sql\",\n\t\t\t\t\"V1.1.1__.sql\",\n\t\t\t\t\"V2__.sql\",\n\t\t\t\t\"V2.1.0__.sql\",\n\t\t\t\t\"V3__.sql\",\n\t\t\t\t\"V11__.sql\",\n\t\t\t\t\"V11.11.11__.sql\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"liquibase\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\td, err := sqltool.NewLiquibaseDir(\"testdata/liquibase\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t}(),\n\t\t\tfiles: []string{\n\t\t\t\t\"1_initial.sql\",\n\t\t\t\t\"2_second_migration.sql\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"dbmate\",\n\t\t\tdir: func() migrate.Dir {\n\t\t\t\td, err := sqltool.NewDBMateDir(\"testdata/dbmate\")\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn d\n\t\t\t}(),\n\t\t\tfiles: []string{\n\t\t\t\t\"1_initial.sql\",\n\t\t\t\t\"2_second_migration.sql\",\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tsum, err := tt.dir.Checksum()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, sum, len(tt.files))\n\t\t\tfor i := range tt.files {\n\t\t\t\trequire.Equal(t, tt.files[i], sum[i].N)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc dir(t *testing.T) migrate.Dir {\n\tp := t.TempDir()\n\td, err := migrate.NewLocalDir(p)\n\trequire.NoError(t, err)\n\treturn d\n}\n\nfunc countFiles(t *testing.T, d migrate.Dir) int {\n\tfiles, err := fs.ReadDir(d, \"\")\n\trequire.NoError(t, err)\n\treturn len(files)\n}\n\nfunc requireFileEqual(t *testing.T, d migrate.Dir, name, contents string) {\n\tc, err := fs.ReadFile(d, name)\n\trequire.NoError(t, err)\n\trequire.Equal(t, contents, string(c))\n}\n"
  }
]